Repository navigation
fix(triage-agent): serve only localhost unless unauthenticated access is allowed - #346
Conversation
|
Latest scan for commit: ✅ Security Scan Report (PR Files Only)Scanned Files
Security Scan Results
Threshold: High No security issues detected in your changes. Great job! This scan only covers files changed in this PR. |
|
@strandly-the-agent can you re-review this PR? |
strandly-the-agent
left a comment
There was a problem hiding this comment.
@JackYPCOnline Approve: both findings are fixed, and I re-ran the bypass at e125ece. It no longer works.
- 🔴
/mcp/logsleak: fixed. I ran the same repro against Bedrock, with a victim chatting and reloading their history./mcp/logsnow has 0 full UUIDs and none of the victim's text (name, DOB, symptoms).session_idandmessage_previeware gone fromdetails, and the IDs in messages are cut to709df529…. - 🟡
/agents/statuslisting: fixed. The route is removed and now returns 404.
I also tried to get around the fix: uppercase, urn:uuid:, {…} and no-dash IDs all go through canonical_session_id first, so they're redacted too. The remaining 8-character prefix still leaves about 90 random bits, so it doesn't make a session guessable. I found no other route or log entry that exposes an ID or user text.
What's left is what the README warning already says: there's no user auth, so this protects sessions only by keeping their IDs secret. That's fine for a demo.
Verification
- Backend ran on
127.0.0.1:8000at heade125ece.pip install -r requirements.txtworked on 3.13 without numpy/pandas, and nothing underbackend/imports them. - Repro output:
GET /sessions404,GET /agents/status404, 24 log entries, 0 full UUIDs, victim UUID present 0 times, user text present 0 times. - Artifacts:
strands-agents/samples/pr/346/repro.shandstrands-agents/samples/pr/346/repro-output.txt - Not re-checked: the CloudFormation stack (not deployed, same as before).
Motivation
The triage-agent backend kept every conversation in one process-wide dict keyed by a client-supplied
session_id, and handed those IDs out three ways:GET /sessionslisted them,GET /agents/statuslisted them again, andGET /mcp/logs(polled by the frontend, forwarded by CloudFront) returned log entries carrying each fullsession_idand the first 50 characters of each user message. With an ID, anyone could read (GET /sessions/{session_id}/history) or delete that session. The IDs were short client-generated strings, and/chatfell back to a shared"default"session.Every session now has a random UUID, and nothing returns one to anyone but the session's own client, so a caller can only reach sessions whose ID they already hold. The sample still has no user authentication; the README now says so plainly and points to adding it before real use.
Public API changes
GET /sessionsandGET /agents/statusare removed. The frontend called neither.session_idmust be a UUID; anything else gets a 400. The frontend now generates one withcrypto.randomUUID()and replaces a stored old-format ID.GET /mcp/logsentries shorten session IDs to their first 8 characters and no longer include user message text. This is enforced insideadd_server_log, so it covers every call site.start.shand the frontend dev server bind127.0.0.1by default (HOST/PORToverride). The stack setsHOST=0.0.0.0andPORT=80instead ofsed-patchingmain.py.Template hardening: port 80 accepts only CloudFront's origin-facing prefix list (looked up by a small custom resource, since its ID differs per region), the SSH rule is gone (SSM was already attached), and the instance role drops
s3:*on*andAmazonBedrockFullAccessforbedrock:InvokeModel*ands3:GetObjecton the app package.numpyandpandasare dropped fromrequirements.txt. Nothing imports them, and their pins need Python 3.11+, so on the template's Ubuntu 22.04 (Python 3.10)pip installfailed and the backend never started.Breaking changes
Testing
deploy.shto a personal account (us-west-2), then deleted it. Through CloudFront: chat streamed from Claude Sonnet 4.6 using the narrowed instance role,/mcp/logsheld neither the session's UUID nor the user's text, and no UUID could be harvested.GET /sessionsandGET /agents/statusreturn 404 on the instance. Port 80 on the instance's public IP timed out and port 22 was closed./mcp/logsgave up the victim's UUID and name, and the harvested UUID read and deleted the session.main, a local run lists the session, returns its messages, and deletes it with no credential.cfn-linton the template: no new findings.This PR was drafted by an AI coding agent on behalf of the account owner, who reviews it before it leaves draft.