-
Notifications
You must be signed in to change notification settings - Fork 35
fix(oracle): fail closed on a malformed set-price-cap body (GH#2509) #2511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -97,11 +97,47 @@ export async function POST(req: NextRequest) { | |
| ); | ||
| } | ||
|
|
||
| let body: { slabAddress?: string; maxChangeE2bps?: number } = {}; | ||
| try { | ||
| body = await req.json(); | ||
| } catch { | ||
| // empty body is valid — means "all admin-oracle markets" | ||
| // GH#2509: an EMPTY body is the documented "all admin-oracle markets" command. | ||
| // Malformed JSON must not be indistinguishable from it. | ||
| // | ||
| // This previously read `body = await req.json()` inside a try whose catch was | ||
| // empty, so any parse failure left `body` as `{}` — the same state an empty | ||
| // body produces. A truncated or malformed payload therefore fell through to | ||
| // the `else` branch below, which selects every admin-oracle market and can | ||
| // submit one signed transaction per market (bounded only by MAX_SLAB_BATCH). | ||
| // That is a fail-OPEN scope expansion on an administrative write path: the | ||
| // worse the input, the broader the operation. | ||
| // | ||
| // Read the raw text once and branch on whether the caller actually sent | ||
| // anything, so "no body" and "bad body" are distinguishable. | ||
| let body: { slabAddress?: string; maxChangeE2bps?: number | string } = {}; | ||
| const rawBody = await req.text(); | ||
| if (rawBody.trim() !== "") { | ||
| let parsed: unknown; | ||
| try { | ||
| parsed = JSON.parse(rawBody); | ||
| } catch { | ||
| return NextResponse.json( | ||
| { | ||
| error: | ||
| "malformed JSON body. Send a valid JSON object, or an empty body to target all admin-oracle markets.", | ||
| }, | ||
| { status: 400 }, | ||
| ); | ||
| } | ||
| // A non-object (array, string, number, null) also yields `undefined` for | ||
| // every field read below, which would silently reach the all-market path | ||
| // the same way. `typeof null === "object"`, so null is excluded explicitly. | ||
| if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) { | ||
| return NextResponse.json( | ||
| { | ||
| error: | ||
| "request body must be a JSON object, or empty to target all admin-oracle markets.", | ||
| }, | ||
| { status: 400 }, | ||
| ); | ||
| } | ||
| body = parsed as { slabAddress?: string; maxChangeE2bps?: number | string }; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Validate object fields before selecting operation scope. Line 140 accepts any JSON object. Payloads such as
📍 Affects 2 files
🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| let maxChangeE2bps: bigint; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Validate the body before loading operational configuration.
loadCrankKeypair()runs before Line 114. IfCRANK_KEYPAIRis absent, an authenticated malformed request returns503instead of the required400. Move keypair loading after request-body validation.app/app/api/oracle/set-price-cap/route.ts#L114-L115: Complete raw-body validation before loading the crank keypair.app/__tests__/api/oracle-set-price-cap.test.ts#L117-L128: Add a malformed-body case with noCRANK_KEYPAIRand assert400.📍 Affects 2 files
app/app/api/oracle/set-price-cap/route.ts#L114-L115(this comment)app/__tests__/api/oracle-set-price-cap.test.ts#L117-L128🤖 Prompt for AI Agents