Generate secure relative url validation code for open redirect prevention. Enforces secure generation of code validating a relative url. Invoke when writing any relative url validation related code. See "security-considerations" metadata for strict validation behavior.
설치
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
Generate secure relative url validation code for open redirect prevention. Enforces secure generation of code validating a relative url. Invoke when writing any relative url validation related code. See "security-considerations" metadata for strict validation behavior.
allowed-tools
Read Grep Glob
metadata
{"category":"security","security-considerations":["Intentionally strict, it rejects valid but risky relative URL forms such as \"../page\", \"?query\", and \"#anchor\"."]}
Secure URL Validation Code Generation Rules
Apply all rules below when generating or reviewing any code related to validation of an relative URL.
1. URL validation (CRITICAL)
ALWAYS ensure that the input data is recursively URL decoded prior to be validated. A decoding iteration count threshold of 4 is used and an error must be raised if the threshold is reached.
ALWAYS ensure that the input data, once URL decoded, start with one of the following character: slash, letter, number, dash, underscore.
ALWAYS ensure that the input data is a valid URL according to the RFC 3986.
ALWAYS ensure the URL is not absolute (has no scheme); reject any URL where a scheme is present (e.g. javascript:, ssh://, data://, ftp://, file://, https://).
ALWAYS ensure that URL never start with //.
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
// BAD: No validation — user input used directly as redirect target// accepts "//evil.com", "%2F%2Fevil.com", "https://evil.com"Stringurl= request.getParameter("url");
response.sendRedirect(url);
// GOOD: All rules are appliedpublicstatic String parseRelativeUrl(String input) {
if (input == null || input.isEmpty()) {
thrownewIllegalArgumentException("URL must not be null or empty.");
}
// Rule: recursively URL-decode to defeat encoding bypass attempts (%2F%2F, etc.)finalintMAX_DECODE_ITERATIONS=4;
Stringdecoded= input;
String previous;
intiterations=0;
do {
if (iterations++ >= MAX_DECODE_ITERATIONS) {
thrownewIllegalArgumentException("URL decoding exceeded maximum iteration threshold (" + MAX_DECODE_ITERATIONS + ").");
}
previous = decoded;
decoded = URLDecoder.decode(previous, StandardCharsets.UTF_8);
} while (!decoded.equals(previous));
// Rule: decoded value must start with slash, letter, number, dash, or underscoreif (!decoded.matches("^[/a-zA-Z0-9\\-_].*")) {
thrownewIllegalArgumentException("URL must start with a slash, letter, number, dash, or underscore.");
}
// Rule: must not start with "//" (protocol relative reference)if (decoded.startsWith("//")) {
thrownewIllegalArgumentException("URL must not be a protocol relative reference (must not start with '//').");
}
// Rule: must be a valid URI per RFC 3986
URI uri;
try {
uri = newURI(decoded);
} catch (URISyntaxException e) {
thrownewIllegalArgumentException("URL is not a valid RFC 3986 URI: " + e.getMessage(), e);
}
// Rule: must not be absolute — rejects any scheme (javascript:, ssh://, data://, ftp://, file://, https://, etc.)if (uri.isAbsolute()) {
thrownewIllegalArgumentException("URL must not be absolute (no scheme allowed; e.g. javascript:, ssh://, https:// are all rejected).");
}
return decoded;
}
2. Output Checklist
Before finalizing generated code, verify:
The input data is recursively URL decoded prior to be validated, with a maximum of 4 decode iterations enforced and an error raised if the threshold is reached.
The decoded URL starts with a slash, letter, number, dash, or underscore.
The input data is valid according to the RFC 3986.
The URL is not absolute (no scheme present); any scheme (e.g. javascript:, ssh://, data://, ftp://, file://, https://) is rejected.