--- id: wiki-2026-0508-배수구-sinks title: 배수구 (Sinks) category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Sinks, Taint Sinks, Dangerous Sinks, Vulnerable Functions] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [security, taint-analysis, sast, vulnerabilities, appsec] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: multi framework: Semgrep/CodeQL --- # 배수구 (Sinks) ## 매 한 줄 > **"매 untrusted data 의 dangerous 의 reach 한 곳 — 매 taint analysis 의 endpoint."**. Source (사용자 input) → Flow (변수, 함수 chain) → Sink (eval, exec, SQL, file write). 2026 SAST tooling (CodeQL, Semgrep, Snyk Code) 은 매 이 source-to-sink graph 의 trace — 매 sanitizer 의 absence 의 vulnerability 의 flag. ## 매 핵심 ### 매 sink 의 종류 - **Code execution**: `eval`, `exec`, `Function()`, `os.system`, 매 deserialize. - **SQL**: 매 raw query string concat (`f"SELECT * FROM u WHERE id={id}"`). - **Command**: `subprocess.Popen(shell=True)`, `child_process.exec`. - **Path**: `open(path)` with 매 user-controlled path → traversal. - **HTML/DOM**: `innerHTML`, `document.write` → XSS. - **SSRF**: `requests.get(user_url)` → 매 internal network access. - **Log forging / template**: 매 user input 의 unescape 된 template. ### 매 source 의 종류 - HTTP request body/query/header. - 매 file content (untrusted upload). - 매 environment variable (in shared env). - 매 third-party API response. - 매 message queue payload. ### 매 응용 1. 매 SAST rule 의 author — 매 custom sink 의 register. 2. 매 code review 의 checklist — 매 sink 의 list 의 grep. 3. 매 fuzzing target 의 prioritize — 매 sink 가 most 인 endpoint. ## 💻 패턴 ### Semgrep — custom sink rule ```yaml rules: - id: python-eval-tainted pattern-sources: - pattern: request.$X pattern-sinks: - pattern: eval(...) - pattern: exec(...) pattern-sanitizers: - pattern: ast.literal_eval(...) message: User input 의 eval 의 reach severity: ERROR languages: [python] ``` ### CodeQL — taint tracking ```ql import python import semmle.python.dataflow.new.TaintTracking class UserInputToSqlConfig extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node n) { n.asExpr().(Attribute).getAttr() in ["args", "form", "json"] } override predicate isSink(DataFlow::Node n) { exists(Call c | c.getFunc().(Attribute).getAttr() = "execute" | n.asExpr() = c.getArg(0)) } } ``` ### SQL sink — parameterize (fix) ```python # BAD — sink reachable db.execute(f"SELECT * FROM users WHERE id = {user_id}") # GOOD — sink 의 sanitize (parameterized) db.execute("SELECT * FROM users WHERE id = %s", (user_id,)) ``` ### Command sink — avoid shell ```python # BAD subprocess.run(f"ping {host}", shell=True) # GOOD subprocess.run(["ping", "-c", "1", host], shell=False) ``` ### Path traversal sink — resolve + check ```python import os base = "/var/uploads" path = os.path.realpath(os.path.join(base, user_filename)) if not path.startswith(base + os.sep): raise PermissionError("path traversal") open(path, "rb") ``` ### XSS sink — escape ```javascript // BAD el.innerHTML = userBio; // GOOD — DOM API el.textContent = userBio; // 또는 매 DOMPurify 의 sanitize 후 el.innerHTML = DOMPurify.sanitize(userBio); ``` ### SSRF — allowlist ```python from urllib.parse import urlparse ALLOWED_HOSTS = {"api.partner.com", "img.cdn.com"} def safe_fetch(url): host = urlparse(url).hostname if host not in ALLOWED_HOSTS: raise ValueError("blocked host") # 매 DNS rebinding 의 also guard — 매 resolve + IP check return requests.get(url, timeout=5) ``` ### Deserialize sink — never on untrusted ```python # BAD — pickle 의 RCE data = pickle.loads(request.body) # GOOD — JSON only data = json.loads(request.body) ``` ## 매 결정 기준 | Sink type | Sanitizer | Notes | |---|---|---| | SQL | Parameterized query, ORM | 매 string concat 의 X | | Shell | argv list, no `shell=True` | 매 quoting 의 trust 의 X | | Path | realpath + prefix check | symlink 의 also handle | | HTML | textContent or DOMPurify | 매 innerHTML 매 last resort | | Eval | 매 그냥 사용 X | 매 alternative 의 find | | Deserialize | JSON only on untrusted | pickle/yaml.load 매 X | **기본값**: 매 sink 의 see 한 후 매 source 의 trace — 매 sanitizer 의 between 의 verify. ## 🔗 Graph - 부모: [[Application_Security]] - 변형: [[SAST]] · [[보안_및_시스템_신뢰성_표준|DAST]] · [[IAST]] - 응용: [[OWASP_Top_10]] - Adjacent: [[Fuzzing]] ## 🤖 LLM 활용 **언제**: 매 unfamiliar codebase 의 sink inventory 의 quickly 의 generate, 매 PR 매 new sink 의 introduce 의 spot. **언제 X**: 매 production-grade SAST 의 replace — 매 LLM 의 false negative 의 risk, 매 dedicated tooling 의 use. ## ❌ 안티패턴 - **Blacklist sanitizer**: 매 known-bad 의 remove — 매 bypass 의 always exist. - **Sanitize at sink**: 매 throughout flow 의 mutate — 매 single point 의 trust 의 X. - **Trust 매 internal**: 매 internal API 의 source 의 also treat — 매 SSRF · Confused deputy. - **Generic exception**: 매 sanitizer fail 의 silent swallow — 매 fail closed. - **String comparison 의 host check**: 매 `endswith("trusted.com")` → `evil-trusted.com` bypass. ## 🧪 검증 / 중복 - Verified (OWASP Source-Sink-Sanitizer model, CodeQL taint tracking docs, Semgrep registry 2026). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — sink categories, SAST rules, sanitizer patterns |