#23294: fix(security): OC-201 Hook Transform RCE - Symlink-Safe Path Containment
docs
gateway
size: M
trusted-contributor
Cluster:
Plugin Management Enhancements
## Summary
Fixes **OC-201** (GHSA-659f-22xc-98f2) - Hook Transform Dynamic Module Import RCE
The hook transform module loader in `hooks-mapping.ts` performed dynamic `import()` on attacker-controlled module paths without symlink-safe path containment. An authenticated attacker could override `hooks.transformsDir` to an arbitrary filesystem location via `config.patch`, then trigger hook execution to achieve Remote Code Execution.
This PR applies two-layer path validation with `fs.realpathSync()` to prevent symlink-based path escape attacks.
## Security Impact
- **Severity:** MEDIUM (CVSS 6.8)
- **CWE:** CWE-94 - Improper Control of Generation of Code ('Code Injection')
- **Attack Vector:** Network (requires authenticated WebSocket session)
- **Impact:** Full RCE as gateway process user
## Changes
1. **Two-layer path validation** in `resolveContainedPath()`:
- Layer 1: Lexical containment check (catches `../` traversal)
- Layer 2: `fs.realpathSync()` symlink resolution with re-validation
- Graceful fallback for ENOENT (file doesn't exist yet)
2. **Defense-in-depth checks**:
- Early rejection of absolute paths outside baseDir
- Restrict `hooks.transformsDir` to configDir subtree via Zod schema
3. **Comprehensive security tests** (6 new tests):
- Symlink bypass prevention
- transformsDir symlink escape detection
- Nested path traversal rejection
- OC-201 specific attack simulation
- ENOENT graceful fallback verification
- Broken symlink handling
## Test Results
All 24 tests pass including new security regression tests:
```
✓ src/gateway/hooks-mapping.test.ts (24 tests) 147ms
```
## References
- Vulnerability Report: OC-201
- GHSA: GHSA-659f-22xc-98f2
- CWE-94: https://cwe.mitre.org/data/definitions/94.html
- Reported by: Aether AI Agent
---
**Attribution:** This fix was implemented by Aether AI Agent (github@tryaether.ai)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Implements comprehensive two-layer path validation to prevent symlink-based RCE attacks in the hook transform module loader. The fix applies defense-in-depth with Zod schema validation to reject absolute paths and path traversal sequences, plus runtime validation using `fs.realpathSync()` to detect symlink escapes.
- Added two-layer path containment validation in `resolveContainedPath()` with lexical checks and canonical path resolution
- Restricted `hooks.transformsDir` config to relative paths without `..` traversal via Zod schema
- Added 6 comprehensive security regression tests covering symlink bypass, absolute path attacks, and ENOENT edge cases
- Gracefully handles non-existent files by falling back to lexical validation when `fs.realpathSync()` fails with ENOENT
The implementation correctly prevents the OC-201 attack vector where authenticated attackers could override `hooks.transformsDir` via `config.patch` and load arbitrary modules. The fix is thorough and well-tested.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge with minimal risk once the severity discrepancy is resolved
- Score reflects a solid security fix with comprehensive test coverage and defense-in-depth approach. Minor issues: severity mismatch between PR description and advisory (needs alignment), and one defense-in-depth check uses string prefix matching instead of proper path validation (not exploitable due to stronger downstream checks). The core two-layer validation with `fs.realpathSync()` correctly prevents symlink-based path escapes, and Zod schema validation blocks absolute paths and traversal sequences at config load time.
- docs/security/OC-201-hook-transform-rce-advisory.md (severity mismatch needs correction)
<sub>Last reviewed commit: 5b51122</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#19542: security: sandbox dynamic import in hook transforms with symlink va...
by Mozzzaic · 2026-02-17
81.7%
#19021: fix(hooks): reject path traversal in hook pack manifest entries dur...
by moxunjinmu · 2026-02-17
79.3%
#8846: fix(tools): block LLM writes to hooks directories
by yubrew · 2026-02-04
75.2%
#23473: Hooks/Plugins: enforce discovery root containment
by bmendonca3 · 2026-02-22
74.8%
#6405: feat(security): Add HTTP API security hooks for plugin scanning
by masterfung · 2026-02-01
73.4%
#21954: Prevent bootstrap hook truncation crash in prompt report
by graysurf · 2026-02-20
73.3%
#11778: fix(plugins): enforce monotonic hook deny merges
by coygeek · 2026-02-08
72.8%
#8124: fix(browser): add path validation for file upload and download
by yubrew · 2026-02-03
72.3%
#23019: fix(hooks): use globalThis singleton for internal hooks handlers Map
by karmafeast · 2026-02-21
72.1%
#23308: fix(browser): accept upload paths that traverse symlinked tmp dirs
by SidQin-cyber · 2026-02-22
71.3%