#1819·repomix

truncateBase64Content silently drops data-URI parameters due to repeated capture group

Author: Poojax21Created Aug 26, 2026Updated Aug 29, 2026
Labelsbuggood first issue

Summary

In src/core/file/truncateBase64.ts, dataUriPattern captures data-URI parameters with a repeated capturing group (;[a-zA-Z0-9\-=]+)*. JavaScript regex semantics keep only the last iteration of a repeated capture group, so a data URI with two or more parameters loses all but the final one when the match is rebuilt in the replace callback. The truncation feature silently corrupts such URIs in the packed output instead of only shortening the base64 payload.

Static-analysis finding based on reading main; not executed here.

Location

  • File: src/core/file/truncateBase64.ts
  • Function: truncateBase64Content (pattern at lines 9-12, callback at lines 55-58)
  • Relevant code:
typescript
const dataUriPattern = new RegExp(
  `data:([a-zA-Z0-9\\/\\-\\+]+)(;[a-zA-Z0-9\\-=]+)*;base64,([A-Za-z0-9+/=]{40,})`,
  'g',
);
...
processedContent = processedContent.replace(dataUriPattern, (_match, mimeType, params, base64Data) => {
  const preview = base64Data.substring(0, TRUNCATION_LENGTH);
  return `data:${mimeType}${params || ''};base64,${preview}...`;
});

Problem

For input data:text/plain;a=1;b=2;base64,AAAA... (payload >= 40 chars):

  1. Group 1 (mimeType) = text/plain.
  2. The repeated group matches twice: first iteration consumes ;a=1, second consumes ;b=2. Per ECMAScript semantics, the group's captured value after the match is the last iteration: ";b=2". ;a=1 is matched but never retained anywhere.
  3. The literal ;base64, then matches, followed by the payload in group 3.
  4. The callback rebuilds the URI as data:text/plain;b=2;base64,<32 chars>... - ;a=1 has been deleted from the user's source content.

The function's contract (shorten long base64 payloads) implies everything outside the payload must be preserved byte-for-byte.

Trigger / Reproduction

Based on source reading:

  1. Run repomix with truncateBase64: true on any repository containing a file with a data URI carrying two parameters, e.g. data:image/png;charset=utf-8;name=x.png;base64,iVBORw0KGgoAAA....
  2. In the output bundle the URI becomes data:image/png;name=x.png;base64,... - the charset=utf-8 parameter is gone.

Expected Behavior

All parameters survive: data:image/png;charset=utf-8;name=x.png;base64,<truncated>....

Actual Behavior

Every parameter except the last is removed whenever more than one is present. Single-parameter URIs are unaffected, which explains why this has gone unnoticed.

Impact

Silent content corruption inside the generated pack: data URIs that consumers round-trip (e.g. embedded SVGs with charset + name, or URIs with vendor-specific flags) become invalid or semantically different after packing, with no warning. Since repomix output is often fed to LLMs/tools as ground truth, corrupted URIs propagate downstream.

Suggested Direction

Make the repeated group non-capturing - (?:;[a-zA-Z0-9\-=]+)* - and capture the full parameter run separately, e.g. wrap it: ((?:;[a-zA-Z0-9\-=]+)*). Then params holds every iteration concatenated, and no other change is needed.

Evidence

  • ECMAScript spec (RegExp [[Match]]): for a quantified capturing group, the final capture state is the one from the last successful iteration.
  • The rebuild path uses only mimeType, params, and base64Data; there is no other mechanism preserving the original prefix of the URI.