Early access. FledgePress is still being built, so things may change.

Static analysis for WordPress plugins, themes and blocks

Before you ship it. Before you install it.

FledgePress reads a WordPress addon inside a sealed container and scores it out of 100 across five categories. Every point it takes off names the problem, the file, and the line.

Any public repository. We clone it read only, and nothing is installed anywhere.

  • No executionYour PHP is read, never run
  • No networkZip scans run with no network at all
  • No accountThe first scan needs nothing from you, zip or repo
Sample reportScan v2
89Grade B
acme-forms
Plugin3 findings
Security70
  • −30eval() lets any string run as codeincludes/render.php:142
Performance100
Code quality100
Compatibility95
  • −5"Requires PHP" version missing from readmereadme.txt
Documentation80
  • −20No changelog found
  • 5categories scored
  • 22checks every scan
  • 0lines of your code run
  • Freehowever often you scan

Who it's for

Nobody reads forty thousand lines of someone else's PHP.

So most WordPress code gets shipped, and gets installed, on trust. This replaces the trust with a report you can argue with.

You're shipping it

The review queue hands your plugin back over an unescaped echo or a missing nonce check. You hear about it days later, fix one line, and rejoin the queue at the end.

Catch that class of problem in seconds, before you submit.

You're installing it

A client site runs thirty plugins by thirty authors. Install counts and star ratings say nothing about what the code does, and you are the one who carries it when something goes wrong.

Scan anything public before it reaches a site you're responsible for.

You inherited it

Whoever built the site is long gone. The plugins directory is full of code nobody has opened in years, some of it written in-house and never reviewed by anyone else.

Get a scored inventory with a file and a line against every problem.

How it works

Three steps, about a minute.

No agent to install and no pipeline to wire up. Submit an addon and read the report.

  1. 01

    Submit

    Paste a public GitHub repo URL, or drop in a .zip of something you have not published. Nothing to install and no config file to write.

    github.com/owner/repoacme-forms.zip
  2. 02

    Isolate

    The addon is unpacked in a throwaway container with no network and hard memory and CPU caps. Its PHP is read as a syntax tree, never run.

    --network none--memory 512m--cpus 1
  3. 03

    Report

    Five category scores, each one 100 minus the findings against it, and the file and line for every finding you can go and fix.

    −30eval() lets any string run as codeincludes/render.php:142

What we check

Here is the whole list.

Every addon meets the same 22 checks, so two scans of the same code always agree. They read a PHP syntax tree, which means commented-out code and strings that merely mention eval never cost you anything.

Every check, and what it costs22 checks

Security

5 checks
  • 30eval() runs a string as code
  • 25shell_exec() and other shell execution
  • 20Superglobal echoed without escaping
  • 15$wpdb query built from a raw string
  • 15$_POST handled without nonce verification

Performance

4 checks
  • 20Database query with no transient caching
  • 15wp_enqueue_scripts not used to enqueue assets
  • 10wp_remote_get() with no caching
  • 5JS or CSS file over 100 KB, up to −20

Code quality

5 checks
  • 20mysqli_query() used instead of $wpdb
  • 15No i18n function anywhere in the addon
  • 10<? short open tags
  • 10split() removed in PHP 7
  • 5Deprecated WordPress function, up to −20

Compatibility

5 checks
  • 20No readme found
  • 15split() unavailable on PHP 7 and later
  • 10Tested up to missing from readme
  • 5Requires at least missing from readme
  • 5Requires PHP missing from readme

Documentation

3 checks
  • 20No changelog found
  • 20Low PHPDoc coverage, or −10 if partial
  • 15No GPL declaration in the plugin header

Next in line

PHPCS with the WordPress standard, PHPStan, Plugin Check, and a vulnerability feed lookup. They add findings to this report rather than change how the score works.

phpcs --standard=WordPress

How scoring works

Every point has a line number.

There are two sums behind the number, and both of them are on this page. Nothing else happens to your score on the way out.

One category100 − findings
100Starting score
30eval() lets any string run as codeincludes/render.php:142
70Security
All fivemean of the categories
Security70
Performance100
Code quality100
Compatibility95
Documentation80
OverallGrade B89
  • Fixed costsThe same finding costs the same on every scan, for every addon
  • Equal weightAll five categories count the same toward the overall score
  • No roundingNothing is nudged in your favour, or against it

Isolation

Your code is never executed.

We treat submitted code as hostile until proven otherwise. This is not a promise about how we behave. It is what the container your scan runs in will actually allow.

The command behind every zip scanone container per job
docker run --rm \
--network none \There is no network device inside to reach
--memory 512m --cpus 1 \Ceilings the kernel enforces, not ones we ask for
--tmpfs /extract:size=50m \Capped, in memory, and gone when the scan ends
-v upload.zip:/work/upload.zip:ro \Your zip, mounted read only
fledgepress-scanner:latestAn image that ships no PHP runtime
A URL scan is the same command with --network bridge, so it can clone the repo and nothing else.

Questions

The things worth asking first.

Including the two that are awkward to answer.

Scan an addon
Is my code ever executed?

No. The scanner parses your PHP into a syntax tree and inspects the tree. There is no PHP runtime in the scanner image, so there would be nothing to execute it with even if something tried to.

Do you keep my code?

No. The addon is unpacked inside a container that is destroyed when the scan ends, and an uploaded zip is deleted as soon as the job finishes. What we keep is the report: the score, the findings, and the file and line each one came from.

Does a good score mean my plugin is secure?

No, and we would rather say so plainly. A score of 100 means this scanner found none of the things it knows how to look for. Static analysis cannot understand intent and cannot see a logic flaw. Treat the report as a floor to clear, not a certificate to hang on the wall.

How is this different from Plugin Check or PHPCS?

Those are excellent, and they are what a reviewer runs. They hand you a list of violations. FledgePress gives you one number you can watch move, across five categories, with a fixed cost per finding, so you can tell whether a change made things better or worse. Running Plugin Check and PHPCS inside the scan is the next thing on our list.

Can I scan a private plugin?

Yes. Upload the .zip, up to 10 MB, and no account is needed for your first scan either way. The zip is unpacked inside the container and deleted from disk as soon as the scan finishes, so nothing has to be published for us to read it.

Can I run it from CI?

Yes. Create an API token in your dashboard and post to the same endpoint the site uses, with the token as a bearer header. The score-diff-on-pull-request flow is specified but not built yet, so for now it is a normal HTTP call you can wire into any pipeline.

What if a finding is wrong?

It happens, and you should be able to tell. Every finding names the check that produced it and the exact line that triggered it, so you can look at the code and judge it yourself. Nothing sits behind a weighting you cannot inspect.

Is it really free?

Yes. A scan costs us a container and a few seconds of CPU. Scanning public addons stays free permanently, because a score nobody can check is not worth much.

Scan an addon.

One free scan without an account, a repo or a zip. Sign up for three a day and every report kept in one place.