# github.com/spf13/afero@v1.15.0 security report (Go)

- Verdict: **Needs review** (risk level: medium)
- Scanned: 2026-10-05T19:10:36.000Z
- Files reviewed: 27
- Findings: 2 high, 7 medium, 6 low severity findings
- Report: https://security.togoder.click/go/github.com/spf13/afero
- Source: Togoder Security (https://security.togoder.click), AI source-code review

## Summary

Togoder Security scanned the Go package github.com/spf13/afero@v1.15.0 on Oct 5, 2026. An AI review of 27 source files produced 2 high, 7 medium, 6 low severity findings. The overall verdict is medium: the findings flag risky but common patterns (dynamic code, unsafe defaults, broad file or network access) rather than confirmed malware.

## Findings

### [high] Symlink-based escape of base path restrictions

Finding ID: `NPS-C40E55DACEBB`

File: `basepath.go:1`

The BasePathFs wrapper does not resolve symlinks and delegates operations (Open, OpenFile, Create, etc.) to the underlying Fs. Because the access boundary is enforced only lexically on the requested path, a pre-existing symlink inside the base directory can redirect file operations outside the intended root, allowing read/write access to arbitrary files on the host filesystem.

### [high] Path traversal / prefix matching weakness

Finding ID: `NPS-7F950625E717`

File: `basepath.go:57`

RealPath uses strings.HasPrefix(path, bpath) to ensure the resolved path stays within the base path. This check is insufficient: a crafted name such as '../basepath_evil' can produce a path like '/base/basepath_evil' that passes the prefix check despite escaping the intended directory. Correct implementations should compare with filepath.Separator boundaries (e.g. path == bpath || strings.HasPrefix(path, bpath+string(filepath.Separator))).

### [medium] Incomplete validation on Windows

Finding ID: `NPS-08F0554B2F0B`

File: `basepath.go:62`

validateBasePathName only rejects absolute Windows paths and performs no checks on other Go runtime platforms, while RealPath never revalidates the joined result against the cleaned base path with a separator-aware comparison. This makes containment enforcement fragile across platforms.

### [medium] Potential Panic

Finding ID: `NPS-1E295EB0680C`

File: `memmap.go:232`

The RemoveAll method calls m.mu.RLock() and then inside the loop calls m.mu.RUnlock() and m.mu.Lock() without proper synchronization, potentially causing a panic due to unlocking an already unlocked mutex or deadlock. This is a reliability issue rather than a security exploit.

### [medium] Improper Lock Handling / Potential Deadlocks and Race Conditions

Finding ID: `NPS-0F888DF150CE`

File: `memmap.go:256`

The Rename method calls m.mu.RUnlock() while holding a read lock, then acquires a write lock, then calls m.mu.RLock() again after unlocking the write lock. However, the deferred m.mu.RUnlock() will also execute, leading to an unlock of an already unlocked mutex (panic) or incorrect lock state. This could cause a panic or data corruption, though not directly malicious.

### [medium] Resource exhaustion / DoS via unbounded in-memory buffering

Finding ID: `NPS-8FE8C5288785`

File: `tarfs/fs.go:57`

The New() function reads every tar entry fully into memory using bytes.Buffer via buf.ReadFrom(t). A malicious tar archive with extremely large entries (or many entries) can exhaust process memory, causing denial of service. There is no size cap or streaming behavior.

### [medium] Panic on malformed input

Finding ID: `NPS-13776A39E1C5`

File: `tarfs/fs.go:61`

The constructor panics ('tarfs: reading from tar' or 'tarfs: size mismatch') when reading a malformed tar stream. Because this is a library used by other software, a crafted tar can crash the entire host process (unrecovered panic), which is a denial-of-service concern in server contexts.

### [medium] Unsafe file permissions

Finding ID: `NPS-A4DF4AFF0098`

File: `util.go:47`

WriteReader, SafeWriteReader, and GetTempDir create directories with mode 0o777, which grants write and execute permissions to all users. This can lead to local privilege escalation or unauthorized file modification.

### [medium] Potential path traversal

Finding ID: `NPS-8FEC7FA160E3`

File: `util.go:110`

GetTempDir uses UnicodeSanitize to remove some characters but still allows '/' and '\', which could potentially be used for directory traversal if subPath is attacker-controlled, though the sanitization restricts many dangerous characters.

### [low] Panic on nil parent

Finding ID: `NPS-2E8D2BCEDFC7`

File: `memmap.go:78`

In unRegisterWithParent, if findParent returns nil, the code calls log.Panic, which will crash the program. This could be triggered by unusual file paths, leading to denial of service. Not malicious but a robustness concern.

### [low] Use of log.Panic

Finding ID: `NPS-42696BCEC1FA`

File: `memmap.go:78`

Use of log.Panic in unRegisterWithParent can cause abrupt termination, which might be exploited for denial of service if an attacker can trigger it. Again, not malicious intent.

### [low] Missing Error Handling

Finding ID: `NPS-3EDA086B9433`

File: `memmap.go:230`

In RemoveAll, the error from unRegisterWithParent is ignored, which could lead to inconsistent state. This is a correctness issue, not a security vulnerability per se.

### [low] Path handling uses filepath.Clean without rejecting traversal

Finding ID: `NPS-DB57275D1F8C`

File: `tarfs/fs.go:25`

splitpath normalizes names with filepath.Clean and filepath.ToSlash but does not reject entries containing '../'. While tarfs is an in-memory FS and afero routes lookups through this map, callers that extract or mirror entries from this FS to the real filesystem could be tricked by traversal-containing names. It is a latent trap for downstream users rather than direct exploitation within this file.

### [low] Malformed tar header handling / size mismatch reliance

Finding ID: `NPS-C8F3E767D139`

File: `tarfs/fs.go:63`

The code trusts hdr.Size to equal the number of bytes read; if the underlying reader is not a proper tar.Reader (e.g., custom reader wrongly typed), behavior is undefined. More importantly, symlink/hardlink entries in a tar are stored as regular File entries without resolving targets, which could mislead consumers about link semantics.

### [low] Panic on error

Finding ID: `NPS-976300837AC1`

File: `util.go:122`

GetTempDir panics if MkdirAll fails, which can crash the program and may be exploitable in contexts where the temp directory path is influenced by untrusted input.

## Files reviewed

- `basepath.go` (medium): The BasePathFs implementation of path confinement relies on a string-prefix comparison that can be bypassed and does not guard against symlink escapes, so it cannot be treated as a reliable sandbox boundary for untrusted filenames.
- `memmap.go` (medium): The code appears to be a legitimate in-memory filesystem implementation with no malicious patterns, but contains several synchronization and error handling issues that could lead to panics or data corruption.
- `tarfs/fs.go` (medium): No direct exfiltration, backdoor, or code execution is present, but the library can be used to trigger memory-exhaustion DoS and process-crashing panics on crafted tar input, and its path normalization may mislead downstream extraction logic.
- `util.go` (medium): No malicious patterns detected, but several insecure coding practices (world-writable permissions, panic on error, potential path traversal) could lead to security issues in certain contexts.
- `afero.go` (safe): Cleared by Jev triage; no further analysis needed
- `cacheOnReadFs.go` (safe): No malicious patterns detected
- `const_bsds.go` (safe): No malicious patterns detected
- `const_win_unix.go` (safe): No malicious patterns detected
- `copyOnWriteFs.go` (safe): No malicious patterns detected; the code is a standard copy-on-write filesystem implementation with no exfiltration, credential harvesting, obfuscation, or backdoor behavior.
- `httpFs.go` (safe): No malicious patterns detected in the httpFs.go file; it implements a standard HTTP file system adapter for afero without any red flags.
- `internal/common/adapters.go` (safe): Cleared by Jev triage; no further analysis needed
- `iofs.go` (safe): Cleared by Jev triage; no further analysis needed
- `ioutil.go` (safe): No malicious patterns detected; this is a legitimate fork of Go's ioutil for the afero filesystem abstraction library.
- `lstater.go` (safe): Cleared by Jev triage; no further analysis needed
- `match.go` (safe): Cleared by Jev triage; no further analysis needed
- `mem/dir.go` (safe): Cleared by Jev triage; no further analysis needed
- `mem/dirmap.go` (safe): Cleared by Jev triage; no further analysis needed
- `mem/file.go` (safe): Cleared by Jev triage; no further analysis needed
- `os.go` (safe): This is a legitimate, well-known Go filesystem abstraction library (afero) that only wraps standard os package functions without any malicious patterns.
- `path.go` (safe): Cleared by Jev triage; no further analysis needed
- `readonlyfs.go` (safe): No malicious patterns detected; this is a standard read-only filesystem wrapper implementing expected permission checks.
- `regexpfs.go` (safe): No malicious patterns detected
- `symlink.go` (safe): Cleared by Jev triage; no further analysis needed
- `tarfs/file.go` (safe): No malicious patterns detected; the code implements a read-only in-memory tar filesystem with no network, exec, credential harvesting, or obfuscation.
- `unionFile.go` (safe): No malicious patterns detected; the code is a legitimate implementation of a union filesystem with no network, credential harvesting, obfuscation, or command execution.
- `zipfs/file.go` (safe): No malicious patterns detected
- `zipfs/fs.go` (safe): No malicious patterns detected; the code is a read-only ZIP filesystem implementation using afero with appropriate permission restrictions.

AI analysis is guidance, not a guarantee. Methodology: https://security.togoder.click/methodology
