Skip to content

ctl:ruleRemoveTarget* rejects any target containing @ (e.g. XPath attribute selectors) #3565

Closed

Description

@fzipi

Summary

The action parser refuses to load a rule when the value of ctl:ruleRemoveTargetByTag (or ctl:ruleRemoveTargetById) contains a @ character. The same rule loads cleanly under ModSecurity v2.

The cause appears to be in the scanner: @ is tokenized as the operator prefix (as in @rx, @detectXSS) and that interpretation leaks into action-value tokenization. Likely in src/parser/seclang-scanner.ll.

Affected

  • libmodsecurity 3.0.15 (owasp/modsecurity-crs:nginx image, current pinned digest)
  • ModSecurity-nginx connector

Reproducer

SecRule REQUEST_URI "@unconditionalMatch" \
    "id:999990,\
    phase:2,\
    pass,\
    nolog,\
    ctl:ruleRemoveTargetByTag=attack-xss; XML://@*"

Expected

Rule loads. XML://@* is a valid ModSecurity XPath target and is accepted as a SecRule variable in the same engine.

Actual

[emerg] "modsecurity_rules_file" directive Rules error.
Line: 6. Column: 47. Expecting an action, got:  @*"

The error column always points at the @.

Bisect

Value passed to ctl:ruleRemoveTargetByTag Result
attack-xss; XML:/* ✓ loads
attack-xss; XML://foo ✓ loads
attack-xss; XML://node ✓ loads
attack-xss; XML:/element ✓ loads
attack-xss; REQUEST_HEADERS:Foo ✓ loads
attack-xss; XML://@* ✗ fails at @
attack-xss; XML://@foo ✗ fails at @
attack-xss; XML://@ ✗ fails at @
attack-xss; ARGS:@foo ✗ fails at @
attack-xss; FOO@BAR ✗ fails at @

So the problematic character is @, regardless of its position or what follows it. Quoting ('…') and backslash escaping (\@) are not honored.

ModSecurity v2 comparison

The same rule loads and runs correctly under Apache + mod_security2 2.9.x.

Impact

ctl:ruleRemoveTargetByTag / ctl:ruleRemoveTargetById cannot be used to runtime-toggle any target that includes a @ — which includes the entire XPath attribute axis (XML://@*, XML://@name, etc.). The only workaround is ctl:ruleRemoveById, which disables the whole rule rather than a single target.

Asks

  1. Allow @ (and ideally the full target/XPath grammar) inside ctl:ruleRemoveTarget* values.
  2. If a scanner change is non-trivial, document the limitation in the v3 reference manual.

Activity

  1. airween commented on May 14, 2026

    @airween
    Member

    @fzipi,

    thanks for reporting this.

    It's a very annoying bug, but I think it's easy to fix (with a minimum modification).

    The problem is that the REMOVE_RULE_BY does not cover the character @.

    Adding the @ solves it partially, but probably it would be much better to split up the tokens for ruleRemoveBy... and ruleRemoveTargetBy... cases.

    And of course, add as many tests as possible.

  2. Jitterx69 commented on May 14, 2026

    @Jitterx69
    Contributor

    @airween

    If nobody’s working on this yet, I’d be down to patch it

  3. airween commented on May 14, 2026

    @airween
    Member

    If nobody’s working on this yet, I’d be down to patch it

    Go for it!

  4. Jitterx69 commented on May 14, 2026

    @Jitterx69
    Contributor

    Hope it helps @airween

  5. etiennemunnich commented on May 30, 2026

    @etiennemunnich

    Hi @fzipi — I'm working on #3526 and it overlaps this issue in the lexer, so flagging before either of us rebases.

    #3526 adds a new scanner token class for the ctl:ruleRemoveTargetById / ByTag value to support COLLECTION:/regex/ patterns:

    REMOVE_RULE_TARGET_VALUE   [0-9A-Za-z_\/\.\-\*\:\;\]\[\$\^\+()|?\\{}]+
    

    Two things relevant here:

    1. It rewrites the same {ACTION_CTL_RULE_REMOVE_TARGET_BY_*} rules this issue points at, so a ctl:ruleRemoveTarget* rejects any target containing @ (e.g. XPath attribute selectors) #3565 fix and feat: regex key support for ctl:ruleRemoveTargetById and ctl:ruleRemoveTargetByTag #3526 will collide on those lines. Worth sequencing deliberately.
    2. My char class omits , (to keep chained ctl: actions splitting on comma) and also does not include @, so feat: regex key support for ctl:ruleRemoveTargetById and ctl:ruleRemoveTargetByTag #3526 as-is does not resolve this — XML:/*/@attr would still be rejected.

    The fix looks like adding @ to the value char class(es): REMOVE_RULE_TARGET_VALUE, and REMOVE_RULE_BY if literal @ should also work there. I'm already in this code, so I can fold that into #3526, or keep it separate — whichever ordering you prefer.

    Regression tests I'd add:

    I'll rebase #3526 on current master regardless.

  6. added 2 commits that reference this issue on Jun 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions