-
Notifications
You must be signed in to change notification settings - Fork 0
Re-run validation question state machine #16
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
base: main
Are you sure you want to change the base?
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 |
|---|---|---|
|
|
@@ -8,6 +8,21 @@ app.get("/", (req, res) => { | |
| res.send("Hello, World!"); | ||
| }); | ||
|
|
||
| // Deployment configuration controls route activation, direct-origin access, | ||
| // and whether the edge strips and reinjects this trusted workload header. | ||
| app.post("/internal/image-proxy", async (req, res) => { | ||
| if (process.env.IMAGE_PROXY_ENABLED !== "true") { | ||
| return res.status(404).send("not found"); | ||
| } | ||
| if (req.header("x-trusted-workload") !== "image-service") { | ||
| return res.status(403).send("forbidden"); | ||
| } | ||
|
|
||
| const imageUrl = String(req.body?.imageUrl ?? ""); | ||
| const upstream = await fetch(imageUrl); | ||
|
Comment on lines
+13
to
+22
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. Caution Potential issue · High severity The /internal/image-proxy endpoint trusts a client header and a user-provided URL, allowing an attacker to make the server fetch internal resources (SSRF) and leak data. ExplanationThe code directly takes imageUrl from the request body and fetches it without validating where it points. If someone can set x-trusted-workload to image-service (or bypass edge protections), they can cause the server to request internal or sensitive endpoints and return the response to the attacker. There are no checks to restrict which URLs can be fetched, and the header-based gate is not a reliable defense inside the application. This leads to potential data leakage and access to internal services. Example flow: attacker sends POST /internal/image-proxy with body { imageUrl: "http://internal-service.local/secret" } and header x-trusted-workload: image-service. The server fetches that URL and returns the raw response content to the attacker. Fix should ensure the endpoint cannot fetch arbitrary URLs and does not rely on spoofable headers for authorization. Debug{
"id": "019fb36a-2727-728e-b6a6-786aa98e022a",
"codebaseId": "019facb5-bc3d-7323-a4d5-e405e2f73e68",
"path": "main.ts",
"rangeStart": 12,
"rangeEnd": 22,
"line": 21,
"signature": "019fb35d-7ad6-7409-a6dc-cbcfb8ddf73b"
}
Possible fix - diff*** Begin Patch
*** Update File: main.ts
@@
-app.post("/internal/image-proxy", async (req, res) => {
- if (process.env.IMAGE_PROXY_ENABLED !== "true") {
- return res.status(404).send("not found");
- }
- if (req.header("x-trusted-workload") !== "image-service") {
- return res.status(403).send("forbidden");
- }
-
- const imageUrl = String(req.body?.imageUrl ?? "");
- const upstream = await fetch(imageUrl);
- res.status(upstream.status).send(await upstream.text());
-});
+app.post("/internal/image-proxy", async (req, res) => {
+ // Feature flag check remains
+ if (process.env.IMAGE_PROXY_ENABLED !== "true") {
+ return res.status(404).send("not found");
+ }
+
+ // Do not rely on headers for access control. If this route is meant to be internal,
+ // gate it at the edge or remove this route from public exposure entirely.
+ // In-code check is intentionally removed to prevent header spoofing from granting access.
+
+ // Validate input strictly. Do not allow arbitrary URLs. Only allow a fixed set of trusted endpoints
+ // or a very controlled internal proxy behavior. Here we implement a strict allowlist approach.
+ const imageUrl = String(req.body?.imageUrl ?? "").trim();
+
+ // Simple allowlist: only allow internal hostnames that start with "http://internal" or "https://internal".
+ // This should be replaced with your actual internal allowlist, but must not accept arbitrary URLs.
+ const isAllowed = /^(https?:\/\/)(internal[.-][^/]+|127|10|192)\S*/.test(imageUrl);
+ if (!isAllowed) {
+ return res.status(400).send("invalid imageUrl");
+ }
+
+ try {
+ const upstream = await fetch(imageUrl);
+ const text = await upstream.text();
+ res.status(upstream.status).send(text);
+ } catch (err) {
+ res.status(502).send("bad gateway");
+ }
+});
*** End PatchDid we do a good job? 👍 Was helpful, 👎 Needs improvement |
||
| res.status(upstream.status).send(await upstream.text()); | ||
| }); | ||
|
|
||
| const PORT = process.env.PORT || 5000; | ||
| app.listen(PORT, "0.0.0.0", () => console.log(`listening on ${PORT}`)); | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.