Skip to content

allowExceptInFunctions / disallowInFunctions silently ignores all but the first entry #400

@spaze

Description

@spaze

Summary

When multiple entries are configured in allowExceptInFunctions (or its aliases disallowInFunctions, allowExceptInMethods, disallowInMethods), only the first entry actually disallows. Any subsequent entries are silently ignored.

Root cause

The loop in Allowed::isAllowed() returns true on the first entry that does not match the current call, instead of continuing through all entries:

foreach ($disallowed->getAllowExceptInCalls() as $call) {
    if (!$this->callMatches($scope, $call)) {
        return true;  // bails out on first non-match
    }
}

With a single entry this works correctly. With [A, B] and the current call being A: the loop reaches B, B does not match, and returns true (allowed) — even though A is in the disallow list.

Expected behavior

Same as allowExceptIn for paths — iterate all entries, return false if any entry matches the current call, return true only after all entries have been checked without a match:

if ($disallowed->getAllowExceptInCalls()) {
    foreach ($disallowed->getAllowExceptInCalls() as $call) {
        if ($this->callMatches($scope, $call)) {
            return false;
        }
    }
    return true;
}

Reproduction

parameters:
    disallowedFunctionCalls:
        -
            function: 'foo()'
            disallowInFunctions:
                - 'Bar::methodA'
                - 'Bar::methodB'

Calling foo() inside Bar::methodA is not reported as forbidden, because the loop reaches Bar::methodB, which does not match, and returns allowed.

Affected config keys

  • allowExceptInFunctions / disallowInFunctions
  • allowExceptInMethods / disallowInMethods

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions