VNX-1021: Improper Restriction of Rendered UI Layers (Clickjacking)
Reports code and configuration that disables, weakens or removes the browser's frame protection (X-Frame-Options, CSP frame-ancestors, Spring Security, helmet, Django, Rails, Rack, Talisman, ASP.NET), so any site can frame the application.
| Field | Value |
|---|---|
| Rule ID | VNX-1021 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Python, Java, JavaScript / TypeScript, PHP, Ruby, Go, C# |
| CWE | CWE-1021 |
| CAPEC | CAPEC-103 |
| ATT&CK | T1185 |
| CWSS vector | CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C |
| Tags | clickjacking x-frame-options csp frame-ancestors cwe-1021 |
| Source | internal/sast/rules/vnx-cwe1021-auto.rego |
Overview
VNX-1021 reports CWE-1021: Improper Restriction of Rendered UI Layers or Frames. The finding is code or configuration that switches off, weakens or removes the browser’s frame protection. Once that protection is gone, any site can load the application in an invisible frame and steer the user’s clicks (clickjacking).
What is reported:
- Spring Security:
frameOptions().disable()andheaders().disable(), in their chained, lambda and method-reference forms, including the chain split over two lines (.frameOptions()orhttp.headers(), then.disable()). - X-Frame-Options set to
ALLOWALL,ALLOW-FROMorALLOW, in Java, JavaScript/TypeScript, Python, PHP, Ruby, Go, C# andWeb.config. Current browsers ignoreALLOW-FROM, so it protects nothing. - The header removed (
removeHeader,header_remove,del,Del,Remove,delete,<remove name=...>), unless the same file sets a restrictive CSPframe-ancestorsinstead. - A CSP
frame-ancestorsdirective whose sources include*,https:orhttp:. - Framework switches: helmet/lusca
frameguard: false,xFrameOptions: falseorframeguardactionallow-from; DjangoX_FRAME_OPTIONSset to anything other thanDENY/SAMEORIGIN, and@xframe_options_exempt; Talisman or Rack::Protectionframe_optionsset to an allow value; Rack::Protection or Sinatraprotectionwithexcept: :frame_options; secure_headersx_frame_options = OPT_OUT; Railsdefault_headersemptied or with the header deleted; echoSecureConfigXFrameOptions: ""; ASP.NET CoreSuppressXFrameOptionsHeader = true.
Not reported: DENY and SAMEORIGIN values, frameOptions().sameOrigin()/deny(), frame-ancestors with 'self', 'none' or named hosts, a header removed in a file that sets a restrictive frame-ancestors, the absence of any frame protection (other rules judge missing headers), test and spec code, comments and log strings.
Why This Matters
A clickjacking page loads the target application in a transparent frame on top of something the user wants to click. The user believes they are clicking the attacker’s page, but the clicks land on the application, where the user is already signed in: “transfer”, “delete account”, “grant access” or “enable webcam”. Frame protection is the only control that stops this. The browser enforces it only when the response says so, so a single disable() or ALLOWALL removes it for every page that response covers.
What Gets Flagged
http.headers().frameOptions().disable(); // FLAGGED
http.headers(h -> h.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)); // FLAGGED
app.use(helmet({ frameguard: false })); // FLAGGED
res.setHeader('Content-Security-Policy', "default-src 'self'; frame-ancestors *"); // FLAGGED
X_FRAME_OPTIONS = 'ALLOWALL' # FLAGGED
@xframe_options_exempt # FLAGGED
def widget(request): ...
use Rack::Protection, except: [:json_csrf, :frame_options] # FLAGGED
What Is Not Flagged
http.headers(h -> h.frameOptions(f -> f.sameOrigin()));
response.setHeader("X-Frame-Options", "DENY");
res.removeHeader('X-Frame-Options');
res.setHeader('Content-Security-Policy', "frame-ancestors 'self' https://partner.example.com");
Remediation
- Send
X-Frame-Options: DENY, orSAMEORIGINif the application frames itself. - Send
Content-Security-Policy: frame-ancestors 'none'(or'self'and the exact partner origins that may embed the page). This replacesALLOW-FROM. - Keep the framework’s frame protection on, and exempt only the specific views that must be embedded, with a named
frame-ancestorslist.
References
- CWE-1021: Improper Restriction of Rendered UI Layers or Frames
- OWASP Clickjacking Defense Cheat Sheet
- MDN: CSP frame-ancestors
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-1021
// nosec vnx-1021
Or record an ignore rule: vulnetix ignore add --rule vnx-1021 --reason "...". See Suppressing findings.