[object Object]

← back to Visual Factory

use DNS-aware SSRF gate on /runs/:id/post-ig

5de52a6b25858ede402777d0735824ac1ab5e3ec · 2026-04-30 23:26:47 -0700 · temp

Files touched

Diff

commit 5de52a6b25858ede402777d0735824ac1ab5e3ec
Author: temp <temp@local>
Date:   Thu Apr 30 23:26:47 2026 -0700

    use DNS-aware SSRF gate on /runs/:id/post-ig
---
 server.js | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/server.js b/server.js
index 029c3ab..4dc595a 100644
--- a/server.js
+++ b/server.js
@@ -550,9 +550,12 @@ app.post('/runs/:id/post-ig', async (req, res) => {
     // ranges, file://, or AWS metadata. Only public http(s) hosts allowed.
     let imageUrl = `http://127.0.0.1:${PORT}/runs/${runId}/png`;
     if (req.body && typeof req.body.image_url === 'string' && req.body.image_url.length) {
-      if (!isAllowedExternalUrl(req.body.image_url)) {
+      // Use the DNS-aware validator: blocks both literal-private hosts AND
+      // hostnames that *resolve* to private/loopback/metadata addresses
+      // (DNS rebinding). The route is already async, so the await is free.
+      if (!(await isAllowedAfterDns(req.body.image_url))) {
         return res.status(400).json({
-          error: 'image_url rejected — must be public http(s); private/loopback/metadata addresses blocked',
+          error: 'image_url rejected — must be public http(s); private/loopback/metadata addresses blocked (DNS-resolved)',
         });
       }
       imageUrl = req.body.image_url;

← 287ac34 apply codex p2/p2/p3 abort-handling fixes  ·  back to Visual Factory  ·  B: pre-fetch user image_url and re-host on loopback (closes 30c6d24 →