Skip to content

Limitations & security

Static analysis cannot find every runtime leak, and this tool does not pretend otherwise. Out of scope for v1:

  • Dynamic property and variable access — $obj->{$name}, $$var, Foo::${$prop}.
  • Reflection and anything that writes state through it.
  • Runtime-generated code — eval(), generated classes, create_function.
  • Third-party packages. vendor/ is not scanned, so state retained inside a dependency is invisible. If a dependency leaks, this tool will not tell you.
  • C extension memory leaks and leaks inside the runtime itself.
  • Complex data flow. A value that reaches a static property through several function calls, an array, or a closure captured elsewhere may be missed.
  • Inherited and trait-provided members. A static property declared in a parent class or a trait is analyzed where it is declared, not once per using class, so inherited instance state can be missed by the container rules.
  • A user function that shadows a built-in. A namespaced function putenv() called unqualified cannot be told apart from the global one, so WS003 may report it. Aliased imports (use function putenv as changeEnv) are resolved correctly.
  • Container bindings whose class is not in the scanned paths are skipped rather than guessed at.
  • Bindings and listeners registered dynamically, from a config array or a loop, are not correlated.
  • Where a memoized value comes from, and how long it lasts. WS001 can prove that self::$x ??= … writes only into an empty slot, but not whether the stored value is a constant or request data, and not how long it survives — an initializer that returns null re-runs every time, and a reset in unscanned code re-opens the slot. See the standard Laravel factory.
  • No runtime detection. Which runtime an application actually uses is never determined; --runtime selects what the analysis reasons about. See these are targets, not detections.
  • Suppression is anchored to the reported line. An inline directive or a baseline entry for a static property keeps applying when the code that assigns it changes, because the fingerprint is built from the declaration.

Position this tool accordingly. It is a

worker-safety risk analyzer

not a

proof of safety.

A clean scan means the known cross-request patterns are absent from the analyzed paths. It does not mean the application is safe to run on a worker. Stage the rollout, watch memory, and recycle workers.

The scanner never executes, includes, autoloads or evaluates the code it analyzes. Source is turned into an AST and nothing more; scan does not bootstrap the analyzed application, and YAML is parsed without object support. See SECURITY.md for the full threat model.