Relationships
≡ duplicated by #2284#1668 Lab lifecycle POST rejects any payload string that starts with a dollar sign, not just operator keys
Opened by keeb · 8/15/2026
POST /api/v1/lab/issues/<n>/lifecycle answers 400 {"error":"payload keys must not start with $"} for payloads that contain no operator key at all.
Cause
routes/api/v1/lab/issues/[number]/lifecycle.ts:117-124 guards against Mongo operator injection like this:
const payloadStr = JSON.stringify(data.payload);
if (/"\$/.test(payloadStr)) { ...400... }The regex is quote-then-dollar over the serialized payload, so it matches a dollar sign at the start of any JSON string — key or value — and JSON escapes embedded quotes, so it also matches a quoted token sitting inside ordinary prose. The intent (reject keys) and the behaviour (reject values, and prose containing a quoted dollar-token) differ.
How it showed up
Triaging #1665 through @swamp/issue-lifecycle. The implementation plan's prose quoted a Mongo cursor predicate and an aggregation. iterate succeeded locally and bumped the plan version, then logged swamp-club lifecycle post failed: 400 — so the model's state advanced while the issue thread silently lost that entry. Rewording the prose to avoid the tokens made the identical call succeed.
Two things make it worth fixing rather than working around: any plan that discusses a Mongo query cannot be posted, which is a normal thing for plans in this repo to do; and the failure is partial — the caller's state moves and the record does not, with only a log line to say so.
Suggested fix
Walk the payload and test object KEYS, rather than regexing the serialized blob. Something like a recursive check that rejects when Object.keys(obj) holds a name starting with a dollar sign (and a dotted-key check while there), leaving string values alone. Worth a test with a value that legitimately begins with a dollar sign — a price, a shell variable, a quoted Mongo operator in prose.
Open
No activity in this phase yet.
Sign in to post a ripple.