A curated collection of security rules for Seqra, a static analysis engine for Java and Kotlin that combines Semgrep-style pattern matching with dataflow/taint analysis.
The repository provides:
- A logically structured set of executable security rules for real-world Java/Kotlin applications
- A shared library of reusable rule components (sources, sinks, propagators, etc.)
- A test suite that validates rule behavior and enforces coverage for all enabled rules
.
├─ rules/java/
│ ├─ security/ # Executable rules run against user code (one file per vulnerability class)
│ └─ lib/ # Reusable rule fragments, not executed directly (marked as lib: true)
└─ test/
└─ src/main/java/
└─ security/ # Rule tests with @PositiveRuleSample / @NegativeRuleSample
All rules that are intended to run on user code live under rules/. Each file groups a class of vulnerability.
Example:
rules/java/security/
command-injection.yaml
sqli.yaml
xss.yaml
xxe.yaml
Characteristics:
- Rules are written in Semgrep-compatible YAML.
- Each rule entry has an
id,severity,message,metadata,languages, and pattern/mode fields (mode: taint,pattern,patterns,pattern-either,pattern-sources,pattern-sinks, etc.). - Rules in
rules/are considered executable unless:options.disabled: <reason>— the rule is disabledoptions.lib: true— the rule is a library component (should normally reside inlib/)
The lib/ directory contains rule fragments that are not executed standalone. They are building blocks (sources, sinks, propagators, etc.) that other rules compose via mode: join or standard taint rules.
Structure is by technology, example:
lib/
java/
generic/
command-injection-sinks.yaml
servlet-sqli-sinks.yaml
servlet-untrusted-data-source.yaml
servlet-xss-sinks.yaml
xxe-sinks.yaml
spring/
jdbc-sqli-sinks.yaml
spring-xss-sinks.yaml
untrusted-data-source.yaml
All library rules are marked:
rules:
- id: java-servlet-untrusted-data-source
options:
lib: true
...Key points:
lib: trueexplicitly marks a rule as non-executable; it will not be run by Seqra as a top-level rule.- Library rules are typically:
- Source definitions (
*untrusted-data-source*) - Sink definitions (
*sinks*) - Propagation or helper patterns shared across multiple vulnerabilities
- Source definitions (
Many rules under rules/ combine multiple library rules using mode: join.
Example (from rules/java/security/ssrf.yaml):
- id: ssrf-in-servlet-app
languages:
- java
mode: join
join:
refs:
- rule: java/lib/generic/servlet-untrusted-data-source.yaml#java-servlet-untrusted-data-source
as: untrusted-data
- rule: java/lib/generic/ssrf-sinks.yaml#java-ssrf-sink
as: sink
on:
- 'untrusted-data.$UNTRUSTED -> sink.$UNTRUSTED'Semantics:
mode: joinderives a composite rule from other rules referenced injoin.refs.refsdefines:rule: path to the library rule file plus#<rule-id>inside that YAMLas: local alias for referencing captures/variables from that rule
ondescribes how to correlate matches from referenced rules:untrusted-data.$UNTRUSTED -> sink.$UNTRUSTEDexpresses a dataflow relationship between the$UNTRUSTEDcaptured in the source rule and the same$UNTRUSTEDcaptured in the sink rule.
This join mode is based on Semgrep's join mode, but Seqra extends it with custom features (such as the -> notation in the on section) to express taint-style flows across multiple rule components.
Rules follow Semgrep syntax and concepts:
- Pattern-based rules:
pattern,patterns,pattern-either,pattern-inside,pattern-not-inside,metavariable-regex, etc.
- Taint-style rules:
mode: taintpattern-sources,pattern-propagators,pattern-sanitizers,pattern-sinks- Dataflow through methods, fields, and variables
- Metadata:
cwe,short-description,full-description(where provided)- External references (OWASP, CWE, upstream rule sources)
- Optional
licenseandprovenance
Rule behavior is validated via Java test snippets under:
test/src/main/java/security/
Each test class declares inline code samples annotated with:
@PositiveRuleSample(...)— code that must trigger a specific rule@NegativeRuleSample(...)— code that must not trigger that rule (not shown above but typically paired with positives)
Annotation usage (conceptually):
@PositiveRuleSample(
value = "java/security/xss.yaml",
id = "xss-in-servlet-app"
)
class SomeServletXssSample {
// vulnerable code here
}The CI helper RuleCoverageCheck (in test/src/main/java/rules/RuleCoverageCheck.java) enforces:
- YAML validity for every file in
rules/:- Root is a map and contains a
ruleslist. - Each rule has a non-blank
id.
- Root is a map and contains a
- Test coverage for all active rules:
- Active rules are those in
rules/where:options.disabledis nottrue, andoptions.libis nottrue
- Each such rule must have at least one
@PositiveRuleSamplereferencing:value = "<relative-path-to-rule-yaml>"(e.g.java/security/xss.yaml)id = "<rule-id>"(the rule'sidvalue)
- Active rules are those in
If any active rule is not covered by a positive sample, or if any YAML is invalid, the checker:
- Prints detailed errors (uncounted rules, invalid YAML, etc.)
- Exits with a non-zero status (breaking the build/CI)
This repository exposes a Gradle verification task:
verification/checkRulesCoverage
Behavior:
- Runs the
RuleCoverageCheckhelper - Ensures:
- All rule YAMLs in
rules/are syntactically valid - Every enabled, non-lib rule has at least one positive test sample
- All rule YAMLs in
Usage (from the test/root subdirectory):
cd test/root
../gradlew verification/checkRulesCoverageOn success:
"Rule coverage check passed: all rules valid and covered."is printed.
On failure:
- It prints all problems (invalid YAML, uncovered rules) and fails the task.
When introducing or changing rules, follow these guidelines:
-
Choose the correct location
- Executable vulnerability rules →
java/security/<vuln-class>.yaml - Shared sources, sinks, or helpers →
java/lib/generic/orjava/lib/spring/
- Executable vulnerability rules →
-
Mark library-only rules
- Add
options.lib: truefor library fragments inlib/(or exceptionally inrules/if they are not meant to be executed directly).
- Add
-
Avoid duplicates
- Reuse existing library rules from
lib/and compose them viamode: joinwhere applicable.
- Reuse existing library rules from
-
Update tests
- Add at least one
@PositiveRuleSample(and typically@NegativeRuleSample) undertest/src/main/java/security/. - Reference the rule by:
value = "<relative YAML path under project root>"id = "<rule id>"
- Add at least one
-
Run coverage checks
- From the
test/rootsubdirectory execute../gradlew verification/checkRulesCoverageto ensure:- No YAML errors
- All executable rules are covered by tests
- From the
This project is licensed under the MIT License — see the LICENSE file for details.
Rule content may incorporate or adapt patterns originally published under various open-source licenses (for example, from community rule sets). Where applicable, original provenance and license information is recorded in rule metadata.