Skip to content

Fix quadratic ReDoS in cURL/Postman import placeholder regexes #788

Description

@pamod-madubashana

Description

I found that pasting a cURL command whose URL contains a long run of { characters makes the import hang the server. CurlParser.parseUrl in packages/backend/src/connectors/parsers/curl.parser.ts:280 runs url.replace(/\{\{([^}]+)\}\}/g, 'PLACEHOLDER_$1') unconditionally over the pasted URL, and the same loose {{([^}]+)}} shape is used on the pasted path, headers and body at lines 108, 141, 155, 156, 183 and 225. That pattern backtracks quadratically on brace runs with no closing }}: each start position scans to the end of the string and fails, so 4x input costs ~16x time. The import endpoint (connectors.controller.ts:1492, this.curlParser.parse(dto.content)) accepts user-supplied content with a 10mb body limit (main.ts:53), and Node runs this on the event loop, so one 80KB paste stalls every request for seconds. The codebase already treats this exact pattern shape as a ReDoS: caller-context.util.ts:26-34 documents that the looser \{\{([^}]+)\}\} backtracks polynomially and uses disjoint character classes instead.

Reproduce

  1. Run this (same regex literal as curl.parser.ts:280, same hostile shape the repo's own specs use):
    node -e "for (const k of [2000,8000,20000]) { const u='https://api.example.com/'+'{{{{'.repeat(k); const t=process.hrtime.bigint(); u.replace(/\{\{([^}]+)\}\}/g,'PLACEHOLDER_$1'); console.log('chars='+u.length+' '+((Number(process.hrtime.bigint()-t)/1e6).toFixed(1))+'ms'); }"
  2. Observed output: chars=8024 46.7ms, chars=32024 719.7ms, chars=80024 4420.8ms -- roughly 16x slower per 4x input, i.e. quadratic.
  3. The equivalent fixed-shape replace (/\{\{\s*([^{}\s]+)\s*\}\}/g) takes 0.1-0.3ms on all three inputs.
  4. End to end, the same input reaches the regex via the connector import: paste curl https://api.example.com/{{{{… (brace run, no closing }}) as a curl import and parseUrl scans the whole URL at curl.parser.ts:280 before any placeholder is found.

Expected

The import parsers should scan pasted text in linear time. The smallest fix is to give the {{…}} patterns disjoint character classes (e.g. [^{}\s] for the variable name, allowing surrounding \s*), exactly as caller-context.util.ts:34 already does, and apply it to every {{([^}]+)}} occurrence in curl.parser.ts, postman.parser.ts, env-interpolation.util.ts, unresolved-placeholders.util.ts, connector-secrets.util.ts and catalog-env-rebuild.util.ts.

Checklist

  • Searched 22 open issues plus closed issues/PRs -- no report about brace-run ReDoS in the import parsers (only unrelated dependency and ReDoS fixes elsewhere)
  • File:line + repro provided

Distinct from fix(security): close the five open CodeQL alerts on main #719 and its follow-up #722, which fixed ReDoS in graphql-builtins.ts slug handling and the OAuth e-mail check -- different files and patterns; the {{…}} occurrences above were not touched by either.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions