{"id":50954016,"url":"https://github.com/aslafy-z/coreruleset-plugins-image","last_synced_at":"2026-06-18T04:33:00.554Z","repository":{"id":365250074,"uuid":"1271138944","full_name":"aslafy-z/coreruleset-plugins-image","owner":"aslafy-z","description":"OWASP CRS plugins as a minimal, signed OCI image for Coraza/Envoy WAFs.","archived":false,"fork":false,"pushed_at":"2026-06-16T13:39:30.000Z","size":38,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-16T15:22:02.420Z","etag":null,"topics":["coraza","coreruleset","cosign","envoy","image-volume","kubernetes","modsecurity","oci-image","owasp-crs","security","slsa","waf"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aslafy-z.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-16T11:22:07.000Z","updated_at":"2026-06-16T13:41:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/aslafy-z/coreruleset-plugins-image","commit_stats":null,"previous_names":["aslafy-z/coreruleset-plugins-image"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/aslafy-z/coreruleset-plugins-image","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aslafy-z%2Fcoreruleset-plugins-image","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aslafy-z%2Fcoreruleset-plugins-image/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aslafy-z%2Fcoreruleset-plugins-image/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aslafy-z%2Fcoreruleset-plugins-image/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aslafy-z","download_url":"https://codeload.github.com/aslafy-z/coreruleset-plugins-image/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aslafy-z%2Fcoreruleset-plugins-image/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34476727,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["coraza","coreruleset","cosign","envoy","image-volume","kubernetes","modsecurity","oci-image","owasp-crs","security","slsa","waf"],"created_at":"2026-06-18T04:33:00.457Z","updated_at":"2026-06-18T04:33:00.549Z","avatar_url":"https://github.com/aslafy-z.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# coreruleset-plugins\n\n[![build-publish](https://github.com/aslafy-z/coreruleset-plugins-image/actions/workflows/build-publish.yml/badge.svg)](https://github.com/aslafy-z/coreruleset-plugins-image/actions/workflows/build-publish.yml)\n[![sync-plugins](https://github.com/aslafy-z/coreruleset-plugins-image/actions/workflows/sync-plugins.yml/badge.svg)](https://github.com/aslafy-z/coreruleset-plugins-image/actions/workflows/sync-plugins.yml)\n[![GHCR](https://img.shields.io/badge/ghcr.io-aslafy--z%2Fcoreruleset--plugins-blue?logo=docker)](https://github.com/aslafy-z/coreruleset-plugins-image/pkgs/container/coreruleset-plugins)\n[![Release](https://img.shields.io/github/v/release/aslafy-z/coreruleset-plugins-image?sort=semver)](https://github.com/aslafy-z/coreruleset-plugins-image/releases/latest)\n[![CRS](https://img.shields.io/badge/CRS-4.x-005571)](https://coreruleset.org)\n[![Signed](https://img.shields.io/badge/cosign-signed-brightgreen?logo=sigstore)](https://www.sigstore.dev)\n\nA single, minimal OCI image that bundles [OWASP Core Rule Set](https://coreruleset.org)\nplugins as plain files, ready to deliver to a Web Application Firewall. The image\ncarries plugin files only; the WAF runtime activates the ones it references by\n`Include` directive. Delivery is bundled, activation is on demand.\n\nThe same payload reaches the WAF through whichever path fits your platform:\n\n- **Kubernetes image volume**: mount the image directly, no copy step.\n- **Custom WAF image**: bake the files into your Envoy/Coraza image at build time\n  with a multi-stage `COPY --from`.\n\nA `manifest.json` and a `tar.gz` of the same payload are also attached to every\nGitHub Release for registry-free consumption.\n\nIt pairs naturally with the\n[`coraza-envoy-go-filter`](https://github.com/united-security-providers/coraza-envoy-go-filter)\n(\"Coraza Web Application Firewall implemented as Envoy Go Filter\"), which embeds\nCRS in the compiled filter and loads additional plugin rules from the filesystem.\nPoint the filter's directives at wherever the files land, and the plugins are\navailable without rebuilding the filter.\n\n## Highlights\n\n- **Minimal.** A `FROM scratch` image; its root is `\u003cplugin\u003e/\u003cfiles\u003e` plus a\n  machine-readable `manifest.json`. No shell, no base layer, no attack surface.\n- **Curated and reviewed.** The plugin set lives in `plugins.yaml` and tracks the\n  official [CRS plugin registry](https://github.com/coreruleset/plugin-registry).\n  A nightly job proposes registry and version changes as pull requests; nothing\n  reaches `:latest` without human review.\n- **Reproducible inputs.** Every plugin is pinned to a commit SHA. The build\n  records each archive's SHA-256 and a digest over all build inputs, republishing\n  only when those inputs actually change.\n- **Supply-chain ready.** Images are signed with [cosign](https://www.sigstore.dev)\n  (keyless OIDC) and carry a [SLSA](https://slsa.dev) build-provenance attestation.\n- **Flexible delivery.** Mount as a Kubernetes image volume, or bake into your own\n  WAF image with `COPY --from`. A `manifest.json` and `tar.gz` are also attached to\n  each GitHub Release for registry-free consumption.\n\n## Bundled plugins\n\n\u003c!-- BEGIN BUNDLED PLUGINS --\u003e\n| Plugin | Version | Origin | Commit |\n| --- | --- | --- | --- |\n| [EsadCetiner/iredadmin-rule-exclusions-plugin](https://github.com/EsadCetiner/iredadmin-rule-exclusions-plugin) | 1.0.1 | registry | `d8a982f` |\n| [EsadCetiner/plausible-rule-exclusions-plugin](https://github.com/EsadCetiner/plausible-rule-exclusions-plugin) | 1.0.0 | registry | `67d5d64` |\n| [EsadCetiner/roundcube-rule-exclusions-plugin](https://github.com/EsadCetiner/roundcube-rule-exclusions-plugin) | 1.0.4 | registry | `ed73635` |\n| [EsadCetiner/sogo-rule-exclusions-plugin](https://github.com/EsadCetiner/sogo-rule-exclusions-plugin) | 1.0.4 | registry | `4d0f073` |\n| [coreruleset/antivirus-plugin](https://github.com/coreruleset/antivirus-plugin) | e6b53a7 | registry | `e6b53a7` |\n| [coreruleset/auto-decoding-plugin](https://github.com/coreruleset/auto-decoding-plugin) | 5d096ad | registry | `5d096ad` |\n| [coreruleset/body-decompress-plugin](https://github.com/coreruleset/body-decompress-plugin) | 80e7d9b | registry | `80e7d9b` |\n| [coreruleset/cpanel-rule-exclusions-plugin](https://github.com/coreruleset/cpanel-rule-exclusions-plugin) | 1.0.0 | registry | `2fd1cab` |\n| [coreruleset/database-logging-plugin](https://github.com/coreruleset/database-logging-plugin) | 1f6ea17 | registry | `1f6ea17` |\n| [coreruleset/dokuwiki-rule-exclusions-plugin](https://github.com/coreruleset/dokuwiki-rule-exclusions-plugin) | 1.0.0 | registry | `0099676` |\n| [coreruleset/dos-protection-plugin-modsecurity](https://github.com/coreruleset/dos-protection-plugin-modsecurity) | 98962f1 | registry | `98962f1` |\n| [coreruleset/drupal-rule-exclusions-plugin](https://github.com/coreruleset/drupal-rule-exclusions-plugin) | 1.0.0 | registry | `6771319` |\n| [coreruleset/fake-bot-plugin](https://github.com/coreruleset/fake-bot-plugin) | 1.1.0 | registry | `e7c675e` |\n| [coreruleset/false-positive-report-plugin](https://github.com/coreruleset/false-positive-report-plugin) | b33cfa3 | registry | `b33cfa3` |\n| [coreruleset/google-oauth2-plugin](https://github.com/coreruleset/google-oauth2-plugin) | 1.0.0 | registry | `4434424` |\n| [coreruleset/incubator-plugin](https://github.com/coreruleset/incubator-plugin) | b87b1d2 | registry | `b87b1d2` |\n| [coreruleset/nextcloud-rule-exclusions-plugin](https://github.com/coreruleset/nextcloud-rule-exclusions-plugin) | 1.6.0 | registry | `83ab69f` |\n| [coreruleset/phpbb-rule-exclusions-plugin](https://github.com/coreruleset/phpbb-rule-exclusions-plugin) | 1.0.0 | registry | `5f1e034` |\n| [coreruleset/phpmyadmin-rule-exclusions-plugin](https://github.com/coreruleset/phpmyadmin-rule-exclusions-plugin) | 1.1.0 | registry | `6629e88` |\n| [coreruleset/referer-hardening-plugin](https://github.com/coreruleset/referer-hardening-plugin) | f3220b2 | registry | `f3220b2` |\n| [coreruleset/template-plugin](https://github.com/coreruleset/template-plugin) | 79a4ec5 | registry | `79a4ec5` |\n| [coreruleset/traffic-observation-plugin](https://github.com/coreruleset/traffic-observation-plugin) | 2cde930 | registry | `2cde930` |\n| [coreruleset/wordpress-rule-exclusions-plugin](https://github.com/coreruleset/wordpress-rule-exclusions-plugin) | 1.2.0 | registry | `161bb90` |\n| [coreruleset/xenforo-rule-exclusions-plugin](https://github.com/coreruleset/xenforo-rule-exclusions-plugin) | 1.0.0 | registry | `193288a` |\n| [eilandert/wordpress-hardening-plugin](https://github.com/eilandert/wordpress-hardening-plugin) | 1.1.2 | registry | `2e2c2a5` |\n| [netnea/netnea-crs-upgrading-plugin](https://github.com/netnea/netnea-crs-upgrading-plugin) | 665bb12 | registry | `665bb12` |\n\u003c!-- END BUNDLED PLUGINS --\u003e\n\n## Getting the files onto the WAF\n\nPick the delivery method that fits your platform. Both land the same\n`\u003cplugin\u003e/\u003cfiles\u003e` tree at a path the filter can `Include`.\n\n### Option A: Kubernetes image volume\n\nMounts the image directly, no copy step.\n\n```yaml\n# Pod spec: image volume + the container's mount\nspec:\n  containers:\n    - name: envoy\n      volumeMounts:\n        - name: crs-plugins\n          mountPath: /etc/crs/plugins\n  volumes:\n    - name: crs-plugins\n      image:\n        reference: ghcr.io/aslafy-z/coreruleset-plugins:latest   # or pin :2026.06.0\n```\n\nImage volumes need the `ImageVolume` feature gate (alpha in v1.31, beta and on by\ndefault from v1.35, stable in v1.36) and a runtime that supports it (containerd\n2.0+, CRI-O 1.31+). On v1.31 to v1.34 enable the gate explicitly.\n\n### Option B: Custom WAF image\n\nBake the plugins into your own Envoy/Coraza image at build time. Because this image\nis `FROM scratch`, `COPY --from` pulls its entire root with no shell or copy tooling\ninvolved, and the plugins ship inside your image with nothing to mount at runtime.\n\n```dockerfile\n# Pin a specific version for reproducible builds.\nFROM ghcr.io/aslafy-z/coreruleset-plugins:2026.06.0 AS plugins\n\nFROM your-registry/envoy-coraza:latest\nCOPY --from=plugins / /etc/crs/plugins/\n```\n\nPinning to a tag (rather than `:latest`) keeps the build reproducible while still\nreceiving update PRs from an automated dependency updater (see\n[Versioning](#versioning)).\n\n## Wiring the plugins into the filter\n\nOnce the files are at the mount path, reference them from the filter's directives.\nThis example targets the Coraza Envoy filter.\n\n```yaml\n# Coraza filter directives (Envoy plugin_config TypedStruct)\nplugin_config:\n  \"@type\": type.googleapis.com/xds.type.v3.TypedStruct\n  value:\n    directives:\n      waf1:\n        simple_directives:\n          - \"Include @coraza-setup\"\n          - \"SecRuleEngine On\"\n          - \"Include @crs-setup\"\n          # Activate only the plugins you need, by name, BEFORE core rules:\n          - \"Include /etc/crs/plugins/wordpress/*-config.conf\"\n          - \"Include /etc/crs/plugins/wordpress/*-before.conf\"\n          - \"Include /etc/crs/plugins/nextcloud/*-config.conf\"\n          - \"Include /etc/crs/plugins/nextcloud/*-before.conf\"\n          - \"Include @owasp_crs/*.conf\"\n          # The same plugins' after-rules, AFTER core rules:\n          - \"Include /etc/crs/plugins/wordpress/*-after.conf\"\n          - \"Include /etc/crs/plugins/nextcloud/*-after.conf\"\n    default_directive: \"waf1\"\n```\n\n\u003e **Activation is per plugin.** The volume delivers every bundled plugin, but the\n\u003e filter loads only the directories you reference, so include the specific plugins\n\u003e you want rather than a `*/*` glob over all of them.\n\u003e\n\u003e **Ordering is load-bearing.** A plugin's `-config` and `-before` files must load\n\u003e *before* `@owasp_crs/*.conf`, and its `-after` files *after* it, so the includes\n\u003e are split around the core rules. The `@` prefix marks resources embedded in the\n\u003e filter; plain filesystem paths reference the mounted volume.\n\n## Image and tarball layout\n\n```\n/                              # image root / tarball root\n├── manifest.json              # generated build record\n├── nextcloud/                 # one directory per plugin\n│   ├── nextcloud-config.conf\n│   └── nextcloud-before.conf\n├── wordpress/\n│   └── ...\n└── ...\n```\n\nEach plugin's files live under a dedicated directory, so filenames never collide.\nThe directory name defaults to the repository basename with the `-plugin` and\n`-rule-exclusions` suffixes stripped (overridable per entry). Placing the root at\n`/etc/crs/plugins` (by mount or extraction) exposes\n`/etc/crs/plugins/\u003cplugin\u003e/\u003cfiles\u003e` with no doubled path segment.\n\n## Verifying provenance\n\n```bash\nIMAGE=ghcr.io/aslafy-z/coreruleset-plugins:latest\n\n# Verify the cosign keyless signature\ncosign verify \"$IMAGE\" \\\n  --certificate-identity-regexp \"https://github.com/aslafy-z/coreruleset-plugins-image/.*\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n\n# Verify the SLSA build-provenance attestation\ncosign verify-attestation \"$IMAGE\" \\\n  --type slsaprovenance \\\n  --certificate-identity-regexp \"https://github.com/aslafy-z/coreruleset-plugins-image/.*\" \\\n  --certificate-oidc-issuer \"https://token.actions.githubusercontent.com\"\n```\n\n## Versioning\n\nTags use CalVer `YYYY.MM.N`, where `N` is an unbounded per-month counter starting\nat `0` and incrementing on every published change. The three numeric segments sort\nas standard `docker` versions, so dependency updaters such as Renovate or\nDependabot order them and open update PRs with no extra configuration. The exact\ncommit and timestamp are recorded in `manifest.json`.\n\n## How it works\n\n| Stage | Trigger | Outcome |\n| --- | --- | --- |\n| **Sync** | Nightly / manual | Reconciles `plugins.yaml` against the CRS registry, resolves each plugin to a commit SHA, opens a reviewed PR. Never publishes. |\n| **Build** | Push to `main` | Downloads each pinned plugin, stages its files, generates `manifest.json`, and computes a build-input digest. Fails closed on any missing or empty plugin. |\n| **Publish** | Push to `main` | Gates on the digest (publish / no-op / repair), allocates the next CalVer tag, pushes to GHCR, signs, attests, renders docs, and creates a GitHub Release. |\n\n`plugins.yaml` is the single source of truth on disk. `manifest.json` is generated\nat build time, embedded in the image, and is the canonical record from which the\nplugin table below and the release notes are derived.\n\n## Local development\n\nThis project uses [mise](https://mise.jdx.dev) for tooling and tasks:\n\n```bash\nmise install        # install pinned tools (yq, jq, shellcheck, cosign, crane)\nmise run sync       # reconcile registry and resolve versions into plugins.yaml\nmise run build      # stage plugins and build manifest.json\nmise run docs       # render the plugin table and release notes\nmise run artifact   # pack the release tarball and checksums\nmise run all        # sync -\u003e build -\u003e docs -\u003e artifact (stamps a dev version)\nmise run lint       # shellcheck all scripts\nmise run clean      # remove generated build artifacts\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faslafy-z%2Fcoreruleset-plugins-image","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faslafy-z%2Fcoreruleset-plugins-image","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faslafy-z%2Fcoreruleset-plugins-image/lists"}