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 server side of the diff fetches, renders, redirects to or validates a URL that input can influence - webhooks, link previews, import-from-URL, PDF renderers, OAuth/JWKS discovery, allowlist and blocklist checks
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Server-side request forgery turns your server into the attacker's network client — inside your VPC, past your firewall, next to the cloud metadata service. Since OWASP Top 10:2025 it sits under A01 Broken Access Control (CWE-918).
Core principle: validate the address you actually connect to, after DNS, on every hop — not the string the user typed.
http://169.254.169.254/latest/meta-data/iam/security-credentials/) answers a plain GET with credentials. IMDSv2 (PUT-token), GCP (Metadata-Flavor: Google) and Azure (Metadata: true) require a header a simple SSRF usually cannot set — check what the deployment runs before calling it CRITICAL.// ❌ substring: "https://example.com.evil.net" and "https://evil.net/?x=example.com" pass
if (!url.includes("example.com")) throw new Error("blocked");
// ❌ suffix without a dot boundary: "https://evilexample.com" passes
if (!new URL(url).hostname.endsWith("example.com")) throw ...
// ❌ regex with an unescaped dot and no end anchor: "https://api.example.com.evil.net"
if (!/^https:\/\/api.example.com/.test(url)) throw ...
// ✅ parse once, compare exact host (or a dot-bounded suffix), fixed scheme
const u = new URL(url);
const ok = u.protocol === "https:" && (u.hostname === "example.com" || u.hostname.endsWith(".example.com"));
Parser tricks that defeat string checks:
https://example.com@evil.net/ — the host is evil.net.https://evil.net\@example.com/ — validators and HTTP clients disagree (WHATWG vs RFC 3986). Validate with the same parser the fetcher uses, or better, the fetcher's resolved address.new URL(userPath, base), Python urljoin(base, user) and Java URI.resolve let //evil.net/x or a full https://evil.net replace the base host.A blocklist on the URL string misses:
http://2130706433/, http://0x7f.1/, http://0177.0.0.1/, http://127.1/, http://0.0.0.0/;http://[::1]/, http://[::ffff:127.0.0.1]/, http://[fd00::1]/;localhost., 127.0.0.1.nip.io, an attacker domain with an A record of 10.0.0.5;127.0.0.1;302 Location: http://169.254.169.254/… and the client follows it.// ✅ the check runs on the address actually dialled — after DNS, on every redirect hop
dialer := &net.Dialer{Control: func(_, address string, _ syscall.RawConn) error {
host, _, _ := net.SplitHostPort(address)
ip := net.ParseIP(host)
if ip == nil || ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || ip.IsUnspecified() {
return errBlockedAddress
}
return nil
}}
client := &http.Client{Transport: &http.Transport{Proxy: nil, DialContext: dialer.DialContext}}
Proxy: nil matters: through a proxy the dialled address is the proxy's, and the check never sees the target. Add any internal ranges the deployment uses (for example 100.64.0.0/10). Node: a request-filtering agent that checks the resolved IP; Python: resolve, check with ipaddress (is_private, is_loopback, is_link_local, is_reserved), then connect to that IP with the original Host header and SNI.
file://, gopher://, dict://, ftp://, Java jar:/netdoc:, and everything libcurl supports. A fetcher that accepts a user URL must restrict the scheme to https (or http/https) before anything else.
<iframe src="http://169.254.169.254/…">, <img src="file:///etc/passwd">.xlink:href; XML parsers with external entities (injection-and-dangerous-sinks); OAuth/OIDC flows fetching a jwks_uri or discovery document from a token-supplied issuer; webhook test buttons; LLM browsing tools whose URL comes from model output (llm-and-agent-security).Full-read SSRF to internal services or credential-bearing metadata → HIGH to CRITICAL. Blind SSRF to an internal network with no known side effect → MEDIUM. Path-only control → not reported.
url.hostname as sufficient while the client follows redirects.fetch(userUrl) in a React component.http.Get(u), requests.get(u), fetch(u), RestTemplate/WebClient, HttpClient.send where u comes from a request body, a stored profile field or a webhook config.includes, contains, endsWith without a leading dot, or an unanchored regex.OWASP Top 10:2025 A01 Broken Access Control · CWE-918 · OWASP API Security Top 10 2023 API7
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
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
日本語の概要は準備中です。原文の説明を表示しています。