agentleFS
mohitkalemohitkale/wordpress-devkit/skills/security-audit/SKILL.md

security-audit

Skill1 starsChanged 4 months agoMITView on GitHub

Audit a WordPress theme or plugin PHP for common vulnerabilities. Use this when the user asks to review a plugin or theme for security, check for XSS, CSRF, SQL injection, or unsafe input handling, or prepare code for submission to wordpress.org. Flags unescaped output, unsafe superglobal handling, missing nonces, unprepared SQL, capability gaps, and missing ABSPATH guards. Produces a grouped pass, warn, and fail report.

192 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use create-stories, story-done and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • lilangMaxSkill

    create-stories

    Break a single epic into implementable story files. Reads the epic, its GDD, governing ADRs, and control manifest. Each story embeds its GDD requirement TR-ID, ADR guidance, acceptance criteria, story type, and test evidence path. Run after /create-epics for each epic.

    Also in 11 projects that use this

  • lilangMaxSkill

    story-done

    End-of-story completion review. Reads the story file, verifies each acceptance criterion against the implementation, checks for GDD/ADR deviations, prompts code review, updates story status to Complete, and surfaces the next ready story from the sprint.

    Also in 11 projects that use this

  • nicepkgSkill

    community-led-growth

    Expert in community-led growth (CLG) - leveraging user communities to drive acquisition, retention, and expansion. Covers building developer communities, user groups, ambassador programs, and turning customers into advocates. Knows the difference between community as a feature vs community as a growth engine, and how to measure community ROI. Use when "community-led, CLG, ambassador program, champion program, user community, developer community, word of mouth, user group, " mentioned.

    Also in 5 projects that use this

  • nicepkgSkill

    ph-community-outreach

    Engage Reddit, Indie Hackers, Hacker News and other communities for Product Hunt launches. Use this skill to identify relevant communities, craft appropriate posts, and drive cross-platform engagement without appearing spammy.

    Also in 5 projects that use this

  • +7 more from lilangMax
  • +1 more from nicepkg

The file

We split this skill into the rules it gives an agent

11 rules. 0 are common, 8 are distinctive, and 3 are very specific to this project.

  • 0

    Common

    Most of the 174 edited versions we read keep these.

  • 8

    Distinctive

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Read every PHP file in the target directory and flag the five most common classes of WordPress security bug.

    line 10
  2. Very specific:

    If $ARGUMENTS is empty, ask for the path.

    line 16
  3. Very specific:

    Use Glob with pattern $ARGUMENTS//*.php to list every PHP file in scope.

    line 20
  4. Very specific:

    Every handler that reads $_POST, writes to the database, or triggers a side effect must verify a nonce.

    line 61
  5. Distinctive:

    Every state change triggered from a user request must be preceded by a capability check:

    line 104
  6. Distinctive:

    Keep file paths relative to the audited directory.

    line 157
  7. Distinctive:

    Do not auto-fix the findings.

    line 175
  8. Distinctive:

    Do not flag a file as a fail based on a single grep pattern without reading the surrounding lines.

    line 176
  9. Distinctive:

    Do not print secret values from the code, even if they appear to be hardcoded keys.

    line 177
  10. Distinctive:

    Do not skip the ABSPATH rule for small files.

    line 178
  11. Distinctive:

    Do not treat every raw superglobal match as a vulnerability.

    line 179

“Common” is measured: kept by at least 6 in 10 of the 174 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Audit WordPress PHP for common vulnerabilities

Read every PHP file in the target directory and flag the five most common classes of WordPress security bug. The report is grouped into pass, warn, and fail so the user knows what to fix first.

Inputs

$ARGUMENTS is the directory to audit. Typically wp-content/themes/<slug> or wp-content/plugins/<slug>.

If $ARGUMENTS is empty, ask for the path.

Workflow

  1. Use Glob with pattern $ARGUMENTS/**/*.php to list every PHP file in scope. Exclude vendor/, node_modules/, and build output.
  2. For each rule below, run the described Grep pattern and collect the matches. Record the file path, line number, and the matching line.
  3. Open any file with a hit to confirm the match is a real issue and not a false positive. A match inside a comment, a string literal used for a fixture, or a code block inside a <pre> example is not a real finding.
  4. Group findings into pass, warn, and fail.
  5. Print the grouped report. Put fails first.

Rules

Rule 1. ABSPATH guard at the top of every PHP file (fail if missing in any loadable file)

Grep for defined.*ABSPATH in each PHP file. Files without the guard are at risk of direct access. Exception: files that cannot be called via HTTP (for example, a PHPUnit test file inside tests/) are a pass.

Expected pattern at the top of every file:

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

Rule 2. Output escaping (fail if any dynamic value is echoed unescaped)

Grep pattern: echo\s+\$ or <\?=\s*\$.

For each hit, confirm the variable is not already wrapped in an escaping function. The escape chosen must match the context:

ContextEscape function
HTML body textesc_html( $var )
HTML attributeesc_attr( $var )
URL in href or srcesc_url( $var )
Text passed to translators then outputesc_html__( 'text', 'textdomain' )
Rich HTML with a known tag allowlistwp_kses( $var, $allowed ) or wp_kses_post( $var )
JSON in a data attributewp_json_encode( $var ) then esc_attr

Unescaped output is a fail. Output that uses the wrong escape for the context is a warn.

Rule 3. Nonce on every state-changing form or AJAX handler (fail if missing)

Grep for $_POST or $_REQUEST or admin-ajax.php.

Every handler that reads $_POST, writes to the database, or triggers a side effect must verify a nonce. Check for one of:

check_admin_referer( 'acme_forms_save' );
check_ajax_referer( 'acme_forms_ajax', 'nonce' );
wp_verify_nonce( $_POST['_wpnonce'], 'acme_forms_save' );

Also check the form side. Every form must include:

wp_nonce_field( 'acme_forms_save' );

Missing nonce on a state-changing handler is a fail. A read-only handler without a nonce is a warn if it reads user input, pass otherwise.

Rule 4. Prepared SQL for any query with user input (fail if missing)

Grep for $wpdb->query, $wpdb->get_results, $wpdb->get_var, $wpdb->get_row.

For each hit, confirm that any dynamic value is passed through $wpdb->prepare with a placeholder (%s, %d, %f). String concatenation into SQL is always a fail.

Correct pattern:

$user_id = absint( $_GET['user_id'] );
$row = $wpdb->get_row(
    $wpdb->prepare( "SELECT * FROM {$wpdb->users} WHERE ID = %d", $user_id )
);

Wrong pattern (fail):

$row = $wpdb->get_row( "SELECT * FROM wp_users WHERE ID = " . $_GET['user_id'] );

Queries with only hardcoded values are a pass and do not need prepare.

Rule 5. Capability check on admin actions (warn if missing)

Grep for functions that change state: update_option, add_option, delete_option, wp_insert_post, wp_delete_post, $wpdb->insert, $wpdb->update, $wpdb->delete.

Every state change triggered from a user request must be preceded by a capability check:

if ( ! current_user_can( 'manage_options' ) ) {
    wp_die( esc_html__( 'Insufficient permissions.', 'acme-forms' ) );
}

Missing capability check on an admin action is a fail. Missing capability check on a public-facing, intentionally open endpoint is a warn with a recommendation to confirm the exposure.

Rule 6. Validate and sanitize input before use (fail when request input reaches a sink unchanged)

Grep for $_GET, $_POST, $_REQUEST, $_COOKIE, $_FILES, and $_SERVER. A superglobal is not automatically a vulnerability: it must be unslashed and validated or sanitized for its intended use before it reaches output, a query, a file operation, an option update, or a redirect.

Expected patterns include:

$name = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '';
$id   = isset( $_GET['id'] ) ? absint( $_GET['id'] ) : 0;
$url  = isset( $_POST['url'] ) ? esc_url_raw( wp_unslash( $_POST['url'] ) ) : '';

Fail when request input reaches a sink unchanged. Warn when the context needs a stricter validator (for example, a URL accepted with sanitize_text_field) or when a read-only endpoint handles user input without an obvious purpose. A raw superglobal that is only checked with isset() before being sanitized is a pass.

Report format

Print one grouped report. Use this structure:

Security audit: acme-forms
Files scanned: 14

FAIL (3)
  includes/save.php:22   Unescaped echo of $_POST['name']. Wrap with esc_html.
  includes/save.php:31   Nonce missing on state-changing POST handler.
  includes/list.php:44   SQL query concatenates $_GET['id'] directly. Use $wpdb->prepare with %d.

WARN (2)
  includes/render.php:12 esc_attr used in HTML body context. Use esc_html.
  admin/settings.php:77  update_option called without current_user_can('manage_options').

PASS (9)
  acme-forms.php             ABSPATH guard present.
  uninstall.php              WP_UNINSTALL_PLUGIN guard present.
  includes/class-main.php    ABSPATH guard present. No dynamic output.
  includes/forms.php         All echoed values escaped, nonce present, prepared SQL.
  includes/shortcodes.php    Output wrapped in wp_kses_post. Static SQL only.
  includes/helpers.php       No output, no SQL, no superglobal reads.
  includes/rest.php          permission_callback checks current_user_can.
  admin/menu.php             current_user_can('manage_options') check present.
  admin/assets.php           No dynamic output. wp_enqueue_script uses a fixed handle.

Keep file paths relative to the audited directory. Always include line numbers for fails and warns.

Example

User runs /wordpress-devkit:security-audit ./wp-content/plugins/acme-forms.

The skill walks the tree, runs the five rules, and produces the grouped report. The report ends with a one-line summary:

Summary: 3 fail, 2 warn, 9 pass. Address fails before release.

Reference

For the exact WordPress API to use when suggesting a fix, consult reference/security-checklist.md in the plugin root. It is a 20-item checklist covering ABSPATH guards, output escaping by context, input sanitization, SQL preparation, nonces, capability checks, file uploads, XSS, IDOR, CSRF, and more. Read on-demand only when a finding needs a concrete fix recommendation.

Do not

  • Do not auto-fix the findings. This skill reports only. The user fixes the code and re-runs the audit.
  • Do not flag a file as a fail based on a single grep pattern without reading the surrounding lines. False positives destroy trust.
  • Do not print secret values from the code, even if they appear to be hardcoded keys. Report the location and the finding, not the value.
  • Do not skip the ABSPATH rule for small files. Every PHP file that can be loaded via HTTP needs the guard.
  • Do not treat every raw superglobal match as a vulnerability. Confirm the data flow and the intended context before reporting it.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.