Skip to content

fix: resolve SSRF and tainted format string code scanning alerts#27

Open
Copilot wants to merge 3 commits intomainfrom
copilot/implement-security-fixes-plan
Open

fix: resolve SSRF and tainted format string code scanning alerts#27
Copilot wants to merge 3 commits intomainfrom
copilot/implement-security-fixes-plan

Conversation

Copy link
Copy Markdown

Copilot AI commented Mar 19, 2026

Addresses the CodeQL alerts left open after PR finos#2239 was closed without merging, incorporating all Copilot review feedback into a clean implementation.

Description

Tainted format string (js/tainted-format-string)

Moves user-controlled values out of the console.error() format-string position in calm-service.tsx (9 instances) and adr-service.tsx (3 instances):

// before
console.error(`Error fetching pattern IDs for namespace ${namespace}:`, error);

// after
console.error('Error fetching pattern IDs for namespace:', namespace, error);

SSRF – DirectUrlDocumentLoader (js/request-forgery)

Adds isPrivateHost() guard before every outbound HTTP request. Key design points vs. the closed PR:

  • All imports at topimport { isIPv4 } from 'net' moved out of class body
  • Full IPv6 coverage:: unspecified address blocked; link-local covers the full fe80::/10 range (fe80–febf, not just fe80); ULA fc00::/7; IPv4-mapped/compatible/translated forms (URL constructor normalises dotted-decimal to hex groups before we inspect them)
  • Alternate IPv4 forms (0x7f000001, 2130706433, 0177.0.0.1) handled automatically — the WHATWG URL constructor normalises these to standard dotted-decimal before isIPv4() is called
  • maxRedirects: 0 prevents SSRF via 3xx redirect to an internal address
  • isISATAP renamed isV4Translated — the condition detects ::ffff:0:x/96 (IPv4-translated), not ISATAP
  • DNS rebinding limitation documented in JSDoc

SSRF / path traversal – CalmHubDocumentLoader (js/request-forgery)

  • Pre-checks raw documentId for percent-encoded traversal sequences (%2e, %2f, %5c, %25) before the URL constructor resolves them
  • Decodes each path segment individually, validates for .././embedded separators, then re-encodes — avoids the double-encoding bug present in the closed PR
  • decodeURIComponent wrapped in try/catch; throws a descriptive error on malformed percent-encoding

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✅ Test additions or updates

Affected Components

  • CALM Hub UI (calm-hub-ui/)
  • Shared (shared/)

Commit Message Format ✅

fix(shared,calm-hub-ui): resolve SSRF and tainted format string code scanning alerts

Testing

  • I have tested my changes locally
  • I have added/updated unit tests
  • All existing tests pass

24 new parameterised tests cover private/internal URL rejection (IPv4 ranges, IPv6 loopback/unspecified/link-local/ULA/embedded, alternate representations, localhost.). 4 new tests cover percent-encoded and double-encoded path traversal in CalmHubDocumentLoader. CodeQL reports 0 alerts.

Checklist

  • My commits follow the conventional commit format
  • I have updated documentation if necessary
  • I have added tests for my changes (if applicable)
  • My changes follow the project's coding standards

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • calm.finos.org
    • Triggering command: /opt/hostedtoolcache/node/24.14.0/x64/bin/node /opt/hostedtoolcache/node/24.14.0/x64/bin/node --conditions node --conditions development /home/REDACTED/work/architecture-as-code/architecture-as-code/node_modules/tinypool/dist/entry/process.js (dns block)
  • download.cypress.io
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node dist/index.js --exec install (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This closed PR - finos#2239 - attempted to close multiple security vulnerabilities reported on the project, Copilot raised multiple issues on PR review which we never got past - I want you to review the PR and the various comments from Copilot then create a plan for a clean implementation which you will implement and raise a new clean PR

The user has attached the following file paths as relevant context:

  • AGENTS.md

Created from VS Code.


📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.

Copilot AI and others added 2 commits March 19, 2026 13:32
Co-authored-by: rocketstack-matt <66839492+rocketstack-matt@users.noreply.github.com>
Co-authored-by: rocketstack-matt <66839492+rocketstack-matt@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix security vulnerabilities in project fix: resolve SSRF and tainted format string code scanning alerts Mar 19, 2026
Copilot AI requested a review from rocketstack-matt March 19, 2026 13:40
@rocketstack-matt rocketstack-matt marked this pull request as ready for review March 19, 2026 13:42
@rocketstack-matt rocketstack-matt requested review from Copilot and removed request for aidanm3341 March 19, 2026 13:42
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Mitigates outstanding CodeQL security alerts by hardening document loading against SSRF/path traversal and removing tainted format-string usage in UI logging.

Changes:

  • Add private/internal host blocking and redirect disabling to DirectUrlDocumentLoader.
  • Harden CalmHubDocumentLoader against encoded/double-encoded path traversal via segment-wise decode/validate/re-encode.
  • Replace console.error() template-literal first-argument usage with constant strings + separate args; add/extend unit tests.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
shared/src/document-loader/direct-url-document-loader.ts Adds private-host guard, reconstructs request URL, disables redirects; introduces IPv4/IPv6 private host detection helpers.
shared/src/document-loader/direct-url-document-loader.spec.ts Adds parameterized tests asserting rejection of private/internal targets (IPv4/IPv6 + alternate forms).
shared/src/document-loader/calmhub-document-loader.ts Adds raw-input traversal pre-check and safe path reconstruction to prevent encoded traversal/path injection.
shared/src/document-loader/calmhub-document-loader.spec.ts Adds tests for percent-encoded, double-encoded traversal and malformed percent-encoding.
calm-hub-ui/src/service/calm-service.tsx Moves user-controlled values out of console.error() format-string position.
calm-hub-ui/src/service/adr-service/adr-service.tsx Same format-string hardening; updates rejected Error messages to include contextual values safely.
package-lock.json Updates lockfile metadata for @swc/core-* optional platform packages.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

}
// Reconstruct a safe URL from validated components. Disable redirects to prevent
// SSRF via 3xx responses that redirect to internal/private addresses.
const safeUrl = parsedUrl.protocol + '//' + parsedUrl.host + parsedUrl.pathname + parsedUrl.search;
Comment on lines +86 to +92
* Returns true if the given hostname resolves to a private, loopback, link-local,
* or otherwise non-public network address.
*
* NOTE: This is a string-based check on the literal hostname value. It does NOT
* protect against DNS rebinding attacks, where a public-looking hostname later
* resolves to a private IP address. For stronger protection, consider resolving
* the hostname to IP addresses and validating each resolved address.
Comment on lines +57 to +58
// double-encoded percent signs (%25) that could hide traversal after further decoding.
if (documentId.includes('/..') || /(%2e(%2e|\.)|\.%2e|%2f|%5c|%25)/i.test(documentId)) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants