Skip to content

Test: mock-server end-to-end variant proving the step_index injection cannot reach jq / leak the token #50

Description

@daniel-pittman

Context

v1.7.1 fixed a jq-injection / token-exfiltration vector in bb logs: step_index was interpolated raw into a jq program (.values[<step_index>].uuid), so a crafted index like 0].uuid,$ENV.BB_TOKEN,.values[0 could make jq emit $ENV.BB_TOKEN. The fix added _require_step_index (a numeric guard) that runs before the interpolation.

v1.7.2 added tests/bash/test_security_guards.sh, run under the digest-pinned bash:3.2 image in the bash32-floor CI job. It asserts each _require_* guard rejects its injection vector by matching the guard's specific error message. That harness is offline by design: every malicious case is rejected before any network call, so it needs no live workspace and no jq / curl / git.

The gap

Because the harness is offline, it proves the guard is present (delete the _require_step_index call and the harness fails), but it cannot prove the end-to-end property that even if a value reached the jq interpolation, the token could not leak. Input only reaches jq if the guard is already broken, and the guard-deletion case is the realistic regression the shipped harness already catches. This is the more exotic remaining scenario: a guard replaced by something that still lets input through to jq.

Proposed work

Add a mock-server variant that drives the injection all the way to the jq step and asserts the token sentinel never appears in output:

  1. A small local HTTP stub with method/path routing (a ~30-50 line python3 http.server handler, or a bats + nc fixture) that returns a canned pipelines list + steps JSON so cmd_logs proceeds past the fetches to the jq interpolation. python3 -m http.server alone will not do path/method routing.
  2. Point BB_API_BASE at http://127.0.0.1:<port>.
  3. Assert: with the guard present, the malicious step_index is rejected; and as a defense-in-depth check, the BB_TOKEN sentinel is absent from output on the injection path.

Constraints / notes

  • This variant cannot run in the minimal bash:3.2 CI image the current harness uses: reaching the jq step requires jq + curl to fetch and parse the mock response. It needs a fuller environment, so it would be a separate CI job on the ubuntu runner (which has python3, jq, curl), not part of bash32-floor.
  • Mock servers carry port-binding and process-cleanup considerations; the fixture must bind an ephemeral port and clean up reliably.

Priority

Low. The security property is already protected by three layers: the guard itself (primary), the CLAUDE.md "destructive/injection-prone values are validated at the boundary" convention (prevents new gaps), and the shipped bash32-floor harness (catches the realistic guard-deletion regression). This variant closes a theoretical corner case at a meaningfully higher infrastructure cost, so it is best done opportunistically if/when a broader bash integration-test harness is stood up, rather than as a standalone piece.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions