Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
日本語の概要は準備中です。原文の説明を表示しています。
Use when the diff builds a filesystem path from input, extracts an archive, accepts an upload, serves a file or writes a temp file - traversal, symlinks, zip-slip, upload type and served content-type
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Join, normalize, resolve and clean are lexical: they rewrite a string, they do not ask the filesystem where it points. A path check that runs on the string and an open that runs on the filesystem disagree whenever there is a .., an absolute path, or a symlink.
Core principle: resolve the real path first, then check containment by path components, then open what you checked — or use an API that confines the open itself.
// ❌ HasPrefix on a cleaned string: "/srv/files-private/x" passes for base "/srv/files",
// and a symlink inside base escapes entirely
p := filepath.Join(base, name)
if !strings.HasPrefix(filepath.Clean(p), base) { return errBadPath }
f, _ := os.Open(p)
// ✅ Go 1.24+: the root confines every lookup, symlinks included
root, _ := os.OpenRoot(base)
f, err := root.Open(name)
// older Go: reject non-local names first — filepath.IsLocal(name) (Go 1.20+)
// ❌ normalize() is lexical; a symlink under base still escapes
Path p = base.resolve(name).normalize();
if (!p.startsWith(base)) throw new SecurityException();
// ✅ compare real paths (Path.startsWith is component-wise, String.startsWith is not)
Path real = base.resolve(name).toRealPath();
if (!real.startsWith(base.toRealPath())) throw new SecurityException();
# ❌ os.path.join drops base entirely when name is absolute ("/etc/passwd")
path = os.path.join(UPLOAD_DIR, name)
# ✅
root = Path(UPLOAD_DIR).resolve()
path = (root / name).resolve()
if not path.is_relative_to(root): # Python 3.9+
abort(400)
// ❌ startsWith without a trailing separator; "/data/app-secrets" passes for "/data/app"
const p = path.resolve(base, name); if (!p.startsWith(base)) throw ...
// ✅
const p = path.resolve(base, name); if (!p.startsWith(base + path.sep)) throw ...
// and for symlinks: fs.realpathSync(p) before the check
Flask: send_from_directory. Express: res.sendFile(name, { root: base }) (rejects escaping paths) rather than res.sendFile(path.join(base, name)).
Lexical checks never see a symlink. It matters when the attacker can create files inside the base (an upload directory, an extracted archive, a cloned repository, a shared volume). Resolve with realpath/EvalSymlinks/toRealPath, or open with O_NOFOLLOW / os.Root. A check-then-open gap on a directory the attacker writes to is a race (CWE-367) — report it only when the attacker demonstrably controls that directory.
Archive entry names are attacker input: ../../.ssh/authorized_keys, absolute paths, and symlink entries that point outside and are then written through.
// ❌
File out = new File(destDir, entry.getName());
Files.copy(zis, out.toPath());
// ✅
Path out = destDir.resolve(entry.getName()).normalize();
if (!out.startsWith(destDir)) throw new IOException("bad entry: " + entry.getName());
tarfile.extractall() without filter="data" (the safe default only from Python 3.14); shutil.unpack_archive on tar. zipfile.extractall sanitises .. and absolute names — not a finding by itself.archive/zip and archive/tar: check filepath.IsLocal(hdr.Name) and skip or reject symlink entries.adm-zip/unzipper/yauzl joining entry.path.Decompression bombs are a resource issue — excluded.
.html or .svg served inline from the app's own origin is stored XSS. Serve user files with Content-Disposition: attachment, a fixed safe Content-Type, X-Content-Type-Options: nosniff, or from a separate cookieless domain.Content-Type and the extension are claims. Allowlist extensions and verify the magic bytes when the type decides how the file is processed (image libraries, document parsers)..env, .git/, source and backups.tenants/B/report.pdf?Predictable names in a shared temp directory (/tmp/export- + userId) let a local attacker pre-create or symlink the file. Use os.CreateTemp, tempfile.mkstemp/NamedTemporaryFile, Files.createTempFile, fs.mkdtemp. Only a finding when other local users or tenants share the machine.
Reading arbitrary server files or writing outside the intended directory → HIGH; CRITICAL when the write reaches code, config or authorized_keys, or the read reaches credentials. Inline-served HTML/SVG upload → HIGH (stored XSS).
filepath.Clean, path.normalize or os.path.normpath as a containment check.<name> converter rejects /, while <path:name> accepts it.Join/resolve followed by a string startsWith/HasPrefix check.entry.getName(), hdr.Name, member.name used to build an output path.extractall( with no filter= on Python < 3.14.file.originalname / filename into the path.Content-Type taken from the upload when serving it back.CWE-22, CWE-59, CWE-367, CWE-377, CWE-434 at cwe.mitre.org · OWASP Top 10:2025 A01 Broken Access Control · ASVS 5.0 V5 File Handling
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
日本語の概要は準備中です。原文の説明を表示しています。
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
日本語の概要は準備中です。原文の説明を表示しています。
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
日本語の概要は準備中です。原文の説明を表示しています。
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
日本語の概要は準備中です。原文の説明を表示しています。
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
日本語の概要は準備中です。原文の説明を表示しています。
Use when deciding whether a request needs an analiz task before implementation - the conditions that require the architect's analysis versus going straight to implementation
日本語の概要は準備中です。原文の説明を表示しています。