commit 510a87fe34e9d435af480458ab9e22be5ad64c56
parent dc9ac3bdaf8525ae458ac38905e34b159b1628a1
Author: Florian Dold <dold@taler.net>
Date: Tue, 21 Jul 2026 11:07:14 +0200
util: escape tab, LF and CR in taler URI path components
The URL parser removes those three before parsing, so ".." followed by a
tab passed the dot-segment guard and then became one inside the parser,
letting a merchant order id erase the merchant host.
Diffstat:
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/packages/taler-util/src/taleruri.ts b/packages/taler-util/src/taleruri.ts
@@ -238,9 +238,9 @@ export namespace TalerUris {
return result;
}
case TalerUriAction.DevExperiment: {
- Object.entries(p.query ?? {}).forEach(([key,value])=> {
- result.push([key,value])
- })
+ Object.entries(p.query ?? {}).forEach(([key, value]) => {
+ result.push([key, value]);
+ });
return result;
}
case TalerUriAction.Refund:
@@ -458,7 +458,8 @@ export namespace TalerUris {
});
}
- const targetPath = firstSlashPos === -1 ? "" : path.slice(firstSlashPos + 1);
+ const targetPath =
+ firstSlashPos === -1 ? "" : path.slice(firstSlashPos + 1);
// withdrawal-transfer-result carries all its data in query parameters and
// so legitimately has no path.
if (
@@ -1168,9 +1169,12 @@ function encodeUriSegment(s: string): string {
}
// Only the characters that would break the positional/query parsing are
// escaped, so that components without them keep their on-the-wire form.
+ // Tab, LF and CR are among them because the URL parser removes them before
+ // parsing, which would otherwise turn "..\t" back into a dot segment.
return s.replace(
- /[%/?#]/g,
- (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`,
+ // eslint-disable-next-line no-control-regex
+ /[%/?#\t\n\r]/g,
+ (c) => `%${c.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0")}`,
);
}