-
-
Notifications
You must be signed in to change notification settings - Fork 53k
Description
Summary
loadTransform() caches hook transform functions by modulePath only, but mappings support multiple exports from the same module. The first loaded export is reused for all later mappings, which can silently apply the wrong security policy (for example, safe vs. unsafe transform logic) across different hook routes.
Affected Code
File: src/gateway/hooks-mapping.ts (line 315)
async function loadTransform(transform: HookMappingTransformResolved): Promise<HookTransformFn> {
const cached = transformCache.get(transform.modulePath);
if (cached) {
return cached;
}
const url = pathToFileURL(transform.modulePath).href;
const mod = (await import(url)) as Record<string, unknown>;
const fn = resolveTransformFn(mod, transform.exportName);
transformCache.set(transform.modulePath, fn);
return fn;
}The cache key on .get() and .set() uses only transform.modulePath, but resolveTransformFn() correctly resolves via transform.exportName. The mismatch means the first export loaded from a module path is returned for all subsequent lookups of that path, regardless of which export was requested.
CVSS Assessment
| Metric | Value |
|---|---|
| Score | 9.1 / 10.0 |
| Severity | Critical |
| Vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:L |
Steps to Reproduce
- Configure two hook mappings that both use
transform.module: ./hooks/transform.jsbut with different exports (e.g.,export: safeTransformandexport: strictTransform). - Send a request that triggers mapping A first, forcing
transformCacheto store A's export function. - Send a request that should trigger mapping B.
- Observe mapping B executing mapping A's transform behavior because cache lookup only uses
modulePath.
Recommended Fix
Cache transforms by a composite key that includes both modulePath and exportName (e.g., ${modulePath}::${exportName ?? "default"}). Add regression tests proving that two mappings sharing one module but different exports execute independently.
References
- CWE: CWE-706 - Use of Incorrectly-Resolved Name or Reference
🤖 Generated with Claude Code
Attack Surface
How is this reached?
- Network (HTTP/WebSocket endpoint, API call)
- Adjacent Network (same LAN, requires network proximity)
- Local (local file, CLI argument, environment variable)
- Physical (requires physical access to machine)
Authentication required?
- None (unauthenticated/public access)
- Low (any authenticated user)
- High (admin/privileged user only)
Entry point: Hook HTTP routes handled through applyHookMappings() when mappings reuse one transform module with different export values.
Exploit Conditions
Complexity:
- Low (no special conditions, works reliably)
- High (requires race condition, specific config, or timing)
User interaction:
- None (automatic, no victim action needed)
- Required (victim must click, visit, or perform action)
Prerequisites:
- Hook mappings include at least two routes referencing the same transform module path with different export functions.