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, except a bomb expanded before any size check on a shared worker by an unauthenticated or low-trust sender (security-hard-exclusions-and-precedents §4).
.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 the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.