Skip to content

fix(telemetry): detect intercepted uploads on client side#70

Open
swarit-stepsecurity wants to merge 1 commit into
step-security:mainfrom
swarit-stepsecurity:swarit/fix/detect-intercepted-uploads
Open

fix(telemetry): detect intercepted uploads on client side#70
swarit-stepsecurity wants to merge 1 commit into
step-security:mainfrom
swarit-stepsecurity:swarit/fix/detect-intercepted-uploads

Conversation

@swarit-stepsecurity
Copy link
Copy Markdown
Member

What does this PR do?

Type of change

  • Bug fix
  • Enhancement
  • Documentation

Testing

  • Tested on macOS (version: ___)
  • Binary runs without errors: ./stepsecurity-dev-machine-guard --verbose
  • JSON output is valid: ./stepsecurity-dev-machine-guard --json | python3 -m json.tool
  • No secrets or credentials included
  • Lint passes: make lint
  • Tests pass: make test

Related Issues

The agent currently treats any HTTP 200 from the presigned-URL PUT as
proof the upload reached S3 and immediately calls notify. A TLS-
inspecting proxy, DLP appliance, or outbound-filtering firewall on a
customer network can terminate that PUT mid-flight and synthesize a
200 response without forwarding the bytes — the run is then reported
as a silent success despite no object ever existing in S3.

Two checks, in order:

1. After the PUT returns 200, require x-amz-request-id and/or x-amz-id-2
   on the response. Real S3 always sets these; a proxy fake-200 can't
   reproduce them. Missing both → non-retryable failure with the
   response Server header captured for forensics.

2. Before calling notify, POST /telemetry/confirm-upload to ask the
   backend whether the object actually exists in S3. A definitive
   uploaded=false is fatal (bail with reason). 404 (old backend
   without the endpoint), non-200, or transport errors fall through
   to notify, whose own server-side precheck remains the safety net.

On success the agent prints a definitive "Upload confirmed in S3 (N
bytes)" line, separate from "Backend processing started", so the user
can tell upload-landed from processing-kicked-off.

Adds tests for: real-S3 happy path, synthetic-200 PUT rejection,
confirm=false fatal path, confirm 404 fallback, confirm 5xx fallback.

Signed-off-by: Swarit Pandey <swarit@stepsecurity.io>
@swarit-stepsecurity swarit-stepsecurity force-pushed the swarit/fix/detect-intercepted-uploads branch from 80fee9c to 7e6c38f Compare May 12, 2026 00:58
@ashishkurmi ashishkurmi requested a review from Copilot May 13, 2026 06:29
proxyHint := putResp.Header.Get("Server")
_, _ = io.Copy(io.Discard, putResp.Body)
_ = putResp.Body.Close()
return fmt.Errorf("S3 PUT returned 200 but the response is not from AWS (missing x-amz-request-id and x-amz-id-2; Server=%q) — the upload likely did not reach S3, possibly intercepted by a TLS-inspecting proxy or outbound firewall on this network", proxyHint)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should log instead of returning an error.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens telemetry S3 uploads against “synthetic 200 OK” responses (e.g., from TLS-inspecting proxies) and adds a backend-assisted confirmation step to detect cases where an upload appeared successful but the object did not actually persist in S3.

Changes:

  • Rejects S3 PUT 200 OK responses that are missing both x-amz-request-id and x-amz-id-2, treating them as non-retryable upload failures.
  • Adds a best-effort /telemetry/confirm-upload call prior to notifying the backend, failing the run only when the backend definitively reports uploaded=false.
  • Expands unit test coverage to validate the new interception detection and confirm-upload compatibility behaviors (success, uploaded=false fatal, 404/5xx fallthrough).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
internal/telemetry/telemetry.go Adds client-side detection of non-AWS “200 OK” PUT responses and introduces a backend confirmation step before notify.
internal/telemetry/telemetry_test.go Adds tests covering synthetic 200 rejection and confirm-upload behavior across success/failure/compat scenarios.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants