-
Notifications
You must be signed in to change notification settings - Fork 1.9k
JS: Move cors-misconfiguration query from experimental to Security #20146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Napalys
merged 15 commits into
github:main
from
Napalys:js/move-cors-query-from-experimental
Sep 8, 2025
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
358617f
Move CORS misconfiguration query from experimental to Security
Napalys 92daa7d
Updated suite expectations
Napalys 95743d7
Added inline test expectations for cors permissive config
Napalys 84ffbbe
Added missing doc strings
Napalys fd4233e
Moved apollo modeling to MaD
Napalys 2baca58
Removed deprecations from cors as it was moved out experimental
Napalys 791a7e2
Updated qhelp for cors permissive configuration
Napalys 021aa13
Added change note
Napalys 4dac80a
Replace complex wrapper classes with MaD
Napalys 6c751ce
Merged config classes
Napalys d3d608f
Updated query description and added a sanitizer
Napalys c4c8dbc
Merge remote-tracking branch 'origin/main' into js/move-cors-query-fr…
Napalys e6eacca
Update change note to reflect changes
Napalys d8c4d6d
Rename `cors-misconfiguration` to `cors-origin`.
Napalys b2feaac
Merge branch 'main' into js/move-cors-query-from-experimental
Napalys File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| extensions: | ||
| - addsTo: | ||
| pack: codeql/javascript-all | ||
| extensible: sinkModel | ||
| data: | ||
| - ["cors", "Argument[0].Member[origin]", "cors-origin"] |
85 changes: 85 additions & 0 deletions
85
javascript/ql/lib/semmle/javascript/security/CorsPermissiveConfigurationCustomizations.qll
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| /** | ||
| * Provides default sources, sinks and sanitizers for reasoning about | ||
| * overly permissive CORS configurations, as well as | ||
| * extension points for adding your own. | ||
| */ | ||
|
|
||
| import javascript | ||
|
|
||
| /** Module containing sources, sinks, and sanitizers for overly permissive CORS configurations. */ | ||
| module CorsPermissiveConfiguration { | ||
| private newtype TFlowState = | ||
| TTaint() or | ||
| TPermissive() | ||
|
|
||
| /** A flow state to associate with a tracked value. */ | ||
| class FlowState extends TFlowState { | ||
| /** Gets a string representation of this flow state. */ | ||
| string toString() { | ||
| this = TTaint() and result = "taint" | ||
| or | ||
| this = TPermissive() and result = "permissive" | ||
| } | ||
| } | ||
|
|
||
| /** Predicates for working with flow states. */ | ||
| module FlowState { | ||
| /** A tainted value. */ | ||
| FlowState taint() { result = TTaint() } | ||
|
|
||
| /** A permissive value (true, null, or "*"). */ | ||
Check warningCode scanning / CodeQL Predicate QLDoc style Warning
The QLDoc for a predicate with a result should start with 'Gets'.
|
||
| FlowState permissive() { result = TPermissive() } | ||
| } | ||
|
|
||
| /** | ||
| * A data flow source for permissive CORS configuration. | ||
| */ | ||
| abstract class Source extends DataFlow::Node { } | ||
|
|
||
| /** | ||
| * A data flow sink for permissive CORS configuration. | ||
| */ | ||
| abstract class Sink extends DataFlow::Node { } | ||
|
|
||
| /** | ||
| * A sanitizer for permissive CORS configuration. | ||
| */ | ||
| abstract class Sanitizer extends DataFlow::Node { } | ||
|
|
||
| /** | ||
| * An active threat-model source, considered as a flow source. | ||
| */ | ||
| private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { | ||
| ActiveThreatModelSourceAsSource() { not this instanceof ClientSideRemoteFlowSource } | ||
| } | ||
|
|
||
| /** An overly permissive value for `origin` configuration. */ | ||
| class PermissiveValue extends Source { | ||
| PermissiveValue() { | ||
| this.mayHaveBooleanValue(true) or | ||
| this.asExpr() instanceof NullLiteral or | ||
| this.mayHaveStringValue("*") | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * The value of cors origin when initializing the application. | ||
| */ | ||
| class CorsOriginSink extends Sink, DataFlow::ValueNode { | ||
| CorsOriginSink() { this = ModelOutput::getASinkNode("cors-origin").asSink() } | ||
| } | ||
|
|
||
| /** | ||
| * A sanitizer for CORS configurations where credentials are explicitly disabled. | ||
| * When credentials are false, using "*" for origin is a legitimate pattern. | ||
| */ | ||
| private class CredentialsDisabledSanitizer extends Sanitizer { | ||
| CredentialsDisabledSanitizer() { | ||
| exists(DataFlow::SourceNode config, DataFlow::CallNode call | | ||
| call.getArgument(0).getALocalSource() = config and | ||
| this = config.getAPropertyWrite("origin").getRhs() and | ||
| config.getAPropertyWrite("credentials").getRhs().mayHaveBooleanValue(false) | ||
| ) | ||
| } | ||
| } | ||
| } | ||
38 changes: 38 additions & 0 deletions
38
javascript/ql/lib/semmle/javascript/security/CorsPermissiveConfigurationQuery.qll
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| /** | ||
| * Provides a dataflow taint tracking configuration for reasoning | ||
| * about overly permissive CORS configurations. | ||
| * | ||
| * Note, for performance reasons: only import this file if | ||
| * `CorsPermissiveConfiguration::Configuration` is needed, | ||
| * otherwise `CorsPermissiveConfigurationCustomizations` should | ||
| * be imported instead. | ||
| */ | ||
|
|
||
| import javascript | ||
| import CorsPermissiveConfigurationCustomizations::CorsPermissiveConfiguration | ||
| private import CorsPermissiveConfigurationCustomizations::CorsPermissiveConfiguration as CorsPermissiveConfiguration | ||
|
|
||
| /** | ||
| * A data flow configuration for overly permissive CORS configuration. | ||
| */ | ||
| module CorsPermissiveConfigurationConfig implements DataFlow::StateConfigSig { | ||
| class FlowState = CorsPermissiveConfiguration::FlowState; | ||
|
|
||
| predicate isSource(DataFlow::Node source, FlowState state) { | ||
| source instanceof PermissiveValue and state = FlowState::permissive() | ||
| or | ||
| source instanceof RemoteFlowSource and state = FlowState::taint() | ||
| } | ||
|
|
||
| predicate isSink(DataFlow::Node sink, FlowState state) { | ||
| sink instanceof CorsOriginSink and | ||
| state = [FlowState::taint(), FlowState::permissive()] | ||
| } | ||
|
|
||
| predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } | ||
|
|
||
| predicate observeDiffInformedIncrementalMode() { any() } | ||
| } | ||
|
|
||
| module CorsPermissiveConfigurationFlow = | ||
| TaintTracking::GlobalWithState<CorsPermissiveConfigurationConfig>; |
73 changes: 73 additions & 0 deletions
73
javascript/ql/src/Security/CWE-942/CorsPermissiveConfiguration.qhelp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| <!DOCTYPE qhelp PUBLIC | ||
| "-//Semmle//qhelp//EN" | ||
| "qhelp.dtd"> | ||
| <qhelp> | ||
|
|
||
| <overview> | ||
| <p> | ||
|
|
||
| A server can use CORS (Cross-Origin Resource Sharing) to relax the | ||
| restrictions imposed by the Same-Origin Policy, allowing controlled, secure | ||
| cross-origin requests when necessary. | ||
|
|
||
| </p> | ||
| <p> | ||
|
|
||
| A server with an overly permissive CORS configuration may inadvertently | ||
| expose sensitive data or enable CSRF attacks, which allow attackers to trick | ||
| users into performing unwanted operations on websites they're authenticated to. | ||
|
|
||
| </p> | ||
| </overview> | ||
|
|
||
| <recommendation> | ||
| <p> | ||
|
|
||
| When the <code>origin</code> is set to <code>true</code>, the server | ||
| accepts requests from any origin, potentially exposing the system to | ||
| CSRF attacks. Use <code>false</code> as the origin value or implement a whitelist | ||
| of allowed origins instead. | ||
|
|
||
| </p> | ||
| <p> | ||
|
|
||
| When the <code>origin</code> is set to <code>null</code>, it can be | ||
| exploited by an attacker who can deceive a user into making | ||
| requests from a <code>null</code> origin, often hosted within a sandboxed iframe. | ||
|
|
||
| </p> | ||
| <p> | ||
|
|
||
| If the <code>origin</code> value is user-controlled, ensure that the data | ||
| is properly sanitized and validated against a whitelist of allowed origins. | ||
|
|
||
| </p> | ||
| </recommendation> | ||
|
|
||
| <example> | ||
| <p> | ||
|
|
||
| In the following example, <code>server_1</code> accepts requests from any origin | ||
| because the value of <code>origin</code> is set to <code>true</code>. | ||
| <code>server_2</code> uses user-controlled data for the origin without validation. | ||
|
|
||
| </p> | ||
|
|
||
| <sample src="examples/CorsPermissiveConfigurationBad.js"/> | ||
|
|
||
| <p> | ||
|
|
||
| To fix these issues, <code>server_1</code> uses a restrictive CORS configuration | ||
| that is not vulnerable to CSRF attacks. <code>server_2</code> properly validates | ||
| user-controlled data against a whitelist before using it. | ||
|
|
||
| </p> | ||
|
|
||
| <sample src="examples/CorsPermissiveConfigurationGood.js"/> | ||
| </example> | ||
|
|
||
| <references> | ||
| <li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin">CORS, Access-Control-Allow-Origin</a>.</li> | ||
| <li>W3C: <a href="https://w3c.github.io/webappsec-cors-for-developers/#resources">CORS for developers, Advice for Resource Owners</a>.</li> | ||
| </references> | ||
| </qhelp> |
22 changes: 22 additions & 0 deletions
22
javascript/ql/src/Security/CWE-942/CorsPermissiveConfiguration.ql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| /** | ||
| * @name Permissive CORS configuration | ||
| * @description Cross-origin resource sharing (CORS) policy allows overly broad access. | ||
| * @kind path-problem | ||
| * @problem.severity warning | ||
| * @security-severity 6.0 | ||
| * @precision high | ||
| * @id js/cors-permissive-configuration | ||
| * @tags security | ||
| * external/cwe/cwe-942 | ||
| */ | ||
|
|
||
| import javascript | ||
| import semmle.javascript.security.CorsPermissiveConfigurationQuery as CorsQuery | ||
| import CorsQuery::CorsPermissiveConfigurationFlow::PathGraph | ||
|
|
||
| from | ||
| CorsQuery::CorsPermissiveConfigurationFlow::PathNode source, | ||
| CorsQuery::CorsPermissiveConfigurationFlow::PathNode sink | ||
| where CorsQuery::CorsPermissiveConfigurationFlow::flowPath(source, sink) | ||
| select sink.getNode(), source, sink, "CORS Origin allows broad access due to $@.", source.getNode(), | ||
| "permissive or user controlled value" |
File renamed without changes.
File renamed without changes.
4 changes: 4 additions & 0 deletions
4
javascript/ql/src/change-notes/2025-07-31-cors-move-out-of-experimental.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| --- | ||
| category: minorAnalysis | ||
| --- | ||
| * The query "Permissive CORS configuration" (`js/cors-permissive-configuration`) has been promoted from experimental and is now part of the default security suite. |
36 changes: 0 additions & 36 deletions
36
javascript/ql/src/experimental/Security/CWE-942/Apollo.qll
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Check warning
Code scanning / CodeQL
Predicate QLDoc style Warning