{"id":50496807,"url":"https://github.com/hubzero/botshield","last_synced_at":"2026-06-02T08:03:51.854Z","repository":{"id":354751773,"uuid":"1224758159","full_name":"hubzero/botshield","owner":"hubzero","description":"Adaptive bot mitigation for the Apache HTTP Server","archived":false,"fork":false,"pushed_at":"2026-04-29T21:48:58.000Z","size":2637,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-29T23:29:29.791Z","etag":null,"topics":["apache","apache-module","bot-detection","captcha","mod-botshield","web-security"],"latest_commit_sha":null,"homepage":"https://hubzero.github.io/botshield/","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hubzero.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"docs/roadmap/index.html","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-04-29T15:43:27.000Z","updated_at":"2026-04-29T21:48:32.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hubzero/botshield","commit_stats":null,"previous_names":["hubzero/botshield"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/hubzero/botshield","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hubzero%2Fbotshield","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hubzero%2Fbotshield/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hubzero%2Fbotshield/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hubzero%2Fbotshield/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hubzero","download_url":"https://codeload.github.com/hubzero/botshield/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hubzero%2Fbotshield/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33812205,"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-02T02:00:07.132Z","response_time":109,"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":["apache","apache-module","bot-detection","captcha","mod-botshield","web-security"],"created_at":"2026-06-02T08:03:50.614Z","updated_at":"2026-06-02T08:03:51.849Z","avatar_url":"https://github.com/hubzero.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs/assets/logo-botshield-header.svg\"\u003e\n    \u003cimg src=\"docs/assets/logo-botshield-header-light.svg\" alt=\"mod_botshield\" width=\"600\"\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eDisciplined Judgment. Proportionate Response.\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/hubzero/botshield/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/hubzero/botshield/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-yellow.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://hubzero.github.io/botshield/\"\u003e\u003cimg src=\"https://img.shields.io/badge/docs-Pages-blue\" alt=\"docs\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://httpd.apache.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/Apache-2.4-D22128?logo=apache\u0026logoColor=white\" alt=\"Apache 2.4 module\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://en.cppreference.com/w/c\"\u003e\u003cimg src=\"https://img.shields.io/badge/language-C99-blue\" alt=\"C99\"\u003e\u003c/a\u003e\n  \u003ca href=\"#whats-shipped\"\u003e\u003cimg src=\"https://img.shields.io/badge/status-beta-orange\" alt=\"status: beta\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nAdaptive bot mitigation for the Apache HTTP Server.\n\nBotShield scores requests, tracks short-term reputation, and decides\nwhether to pass, challenge, slow down, or block before application\ncode has to absorb the traffic.\n\n**Status: beta.** Stable shape, exercising in dev; not yet a production\ndeployment. Architecture, threat model, and per-extension design notes\nlive in [DESIGN.md](DESIGN.md). Site handbook is rendered to\nGitHub Pages from `docs-src/`; see the [documentation index](#documentation)\nbelow.\n\n## What's shipped\n\n- **Tiered challenges.** Pass / silent (no-click auto-submit) / form\n  (checkbox interstitial) / captcha (third-party provider). Per-scope\n  configurable; multi-provider cohabitation on one vhost. Captcha\n  providers: Turnstile, hCaptcha, reCAPTCHA v2 + v3, Friendly Captcha,\n  GeeTest v4.\n- **Cookie envelope.** AES-256-GCM authenticated encryption,\n  per-purpose HKDF-derived keys, verify-only secondary key for\n  graceful rotation. Per-cookie hourly forgiveness cap closes the\n  rebuild-budget evasion. Cookies are session-scoped at the\n  browser layer (no `Expires=` / `Max-Age=`); the server-side\n  `expires_at` field is the hard cap. Every pass through the\n  handler mints `__Host-bs_session` so the next request from the\n  same browser carries an identifier (most cookies carry trust=0\n  — they're per-session markers, not trust receipts).\n- **Sparse server state.** SHM flagged-IP table with seqlock-guarded\n  lockless reads, rotating Bloom filter for first-sight IP signals,\n  crash-durable persistence via `mod_watchdog` snapshots + shutdown\n  save.\n- **Policy.** Path / cookie / env / load / scope / flag triggers\n  (path triggers carry optional UA / IP cohort gates), per-cohort\n  rate limits, in-module robots.txt parser\n  (RFC 9309 + Crawl-delay extension), repeated-429 escalation,\n  anti-loop safeguard (302 redirect to a built-in explainer or to\n  a configured `BotShieldSafeguardRedirectURL` after a client loops\n  on challenges without solving).\n- **Verify-endpoint hardening.** HMAC-signed pending cookie + per-IP\n  rate limit + global in-flight semaphore on `/captcha-verify`.\n  One-time-use nonces + IP-bound bootstrap on the embedded silent\n  path.\n- **Observability.** Structured `key=value` decision-log line per\n  request, 41 Prometheus metrics at `\u003cprefix\u003e/metrics`, `mod_status`\n  contribution hook.\n- **Multi-vhost isolation.** Default-isolate per `ServerName`; opt\n  into shared reputation via `BotShieldShareScope`.\n- **Log-only / shadow mode.** Scope-level `BotShieldEnabled LogOnly`\n  and per-rule `mode=observe` for staging policy changes without\n  enforcement. Counterfactual outcomes (`~challenge`, `~block`,\n  `~rate_limited`) surface in the decision log so you can see what\n  the rule would have done.\n- **Accessibility.** Default interstitial passes WCAG 2.1 AA on every\n  variant.\n\n## Quick start\n\nYou need Apache 2.4 development headers — `apache2-dev` on\nDebian/Ubuntu, `httpd-devel` on RHEL-family.\n\n```sh\nmake enable     # build, install, a2enmod, configtest, reload\n```\n\nStep-by-step equivalents: `make`, `sudo make install`,\n`sudo a2enmod botshield`, `sudo apachectl configtest \u0026\u0026 sudo\nsystemctl reload apache2`. `make disable` removes the module without\ndeleting the `.so`.\n\nMinimal vhost configuration:\n\n```apache\n\u003cVirtualHost *:443\u003e\n    ServerName example.com\n    DocumentRoot /var/www/example\n    # ... SSLEngine, cert files, etc.\n\n    BotShieldEnabled    On\n    BotShieldSecretFile /etc/botshield/secret\n    BotShieldAlgorithm  sha256-zeros\n\u003c/VirtualHost\u003e\n```\n\nGenerate the secret with `openssl rand -hex 32 \u003e /etc/botshield/secret;\nchmod 600 /etc/botshield/secret`. Full setup walkthrough in\n[`docs-src/getting-started.md`](docs-src/getting-started.md).\n\n## Documentation\n\nSite handbook (rendered to\n[hubzero.github.io/botshield](https://hubzero.github.io/botshield/)\nfrom these sources):\n\n| Topic | Source |\n|---|---|\n| Getting started — install, first vhost, smoke test | [`docs-src/getting-started.md`](docs-src/getting-started.md) |\n| Site model — scoring, tiers, cookie reputation, multi-vhost | [`docs-src/site-model.md`](docs-src/site-model.md) |\n| Directives reference | [`docs-src/directives.md`](docs-src/directives.md) |\n| Policy — triggers, rate limits, robots.txt | [`docs-src/policy.md`](docs-src/policy.md) |\n| Captcha tier — providers, hardening, configuration | [`docs-src/captcha.md`](docs-src/captcha.md) |\n| Deployment — reverse proxy, slowloris, capacity sizing, secret rotation | [`docs-src/deployment.md`](docs-src/deployment.md) |\n| Staging policy changes — shadow mode + per-rule observe | [`docs-src/staging.md`](docs-src/staging.md) |\n| Observability — decision log, metrics, mod_status | [`docs-src/observability.md`](docs-src/observability.md) |\n| Troubleshooting | [`docs-src/troubleshooting.md`](docs-src/troubleshooting.md) |\n| FAQ | [`docs-src/faq.md`](docs-src/faq.md) |\n\nInternal references:\n\n- [DESIGN.md](DESIGN.md) — current-state design specification.\n- [CHANGELOG.md](CHANGELOG.md) — date-organized log of changes.\n- [tests/README.md](tests/README.md) — test, fuzz, and benchmark\n  framework.\n\n## Module-owned endpoints\n\nUnder `BotShieldEndpointPrefix` (default `/botshield`):\n\n| Path | Method | Purpose |\n|---|---|---|\n| `\u003cprefix\u003e/captcha-verify` | POST | Bare verify URL (single-provider vhosts) |\n| `\u003cprefix\u003e/captcha-verify/\u003cprovider\u003e` | POST | Per-provider verify URL |\n| `\u003cprefix\u003e/metrics` | GET | Prometheus 0.0.4 text exposition |\n| `\u003cprefix\u003e/policy-status` | GET | Active policy readback (rate limits, block paths, robots.txt) |\n| `\u003cprefix\u003e/embedded.js` | GET | Embedded silent-verify wrapper |\n| `\u003cprefix\u003e/form-widget.js` | GET | Inline form-captcha widget shell |\n| `\u003cprefix\u003e/safeguard-info` | GET | Built-in explainer page rendered when challenge-safeguard trips (and no `BotShieldSafeguardRedirectURL` is set). Accepts `?return=\u003curlencoded path\u003e` |\n\nAccess control is delegated to standard Apache mechanisms — wrap any\nof them in `\u003cLocation\u003e` with `Require ip` / `AuthType Basic` to\nrestrict, e.g.:\n\n```apache\n\u003cLocation /botshield/metrics\u003e\n    Require ip 10.0.0.0/8\n\u003c/Location\u003e\n```\n\n## Local development\n\nThe repo ships a working HTTPS dev vhost at\n`apache/botshield-dev.conf` that exercises every directive against\nthe committed `tests/site/` docroot. Bring it up:\n\n```sh\nsudo tests/setup/provision.sh\n```\n\nIdempotent — safe to re-run. After it completes, the dev vhost\nlistens on `https://localhost/`. Test infrastructure (pytest harness,\nfuzz, benchmarks) is documented in\n[`tests/README.md`](tests/README.md).\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhubzero%2Fbotshield","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhubzero%2Fbotshield","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhubzero%2Fbotshield/lists"}