{"id":19174591,"url":"https://github.com/equalitie/banjax-next","last_synced_at":"2026-03-19T08:30:53.046Z","repository":{"id":45969206,"uuid":"322523187","full_name":"equalitie/banjax-next","owner":"equalitie","description":null,"archived":false,"fork":false,"pushed_at":"2024-09-26T22:32:36.000Z","size":486,"stargazers_count":1,"open_issues_count":7,"forks_count":0,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-10-23T16:48:10.835Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/equalitie.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":"supporting-containers/nginx/Dockerfile","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-18T07:36:30.000Z","updated_at":"2021-10-22T19:22:52.000Z","dependencies_parsed_at":"2025-01-04T01:34:54.975Z","dependency_job_id":"c8350a21-b35f-43f0-b7fa-24bf6d01ab53","html_url":"https://github.com/equalitie/banjax-next","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/equalitie/banjax-next","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/equalitie%2Fbanjax-next","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/equalitie%2Fbanjax-next/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/equalitie%2Fbanjax-next/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/equalitie%2Fbanjax-next/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/equalitie","download_url":"https://codeload.github.com/equalitie/banjax-next/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/equalitie%2Fbanjax-next/sbom","scorecard":{"id":379351,"data":{"date":"2025-08-11","repo":{"name":"github.com/equalitie/banjax-next","commit":"f44aeab6ac1953927cb497792332851d19483c82"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.1,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/23 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/equalitie/banjax-next/test.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/equalitie/banjax-next/test.yml/master?enable=pin","Warn: containerImage not pinned by hash: Dockerfile:7: pin your Docker image by updating golang:1.15.0-buster to golang:1.15.0-buster@sha256:eb93d11dc4e39359ecf290c1bfdf18eea125d93f56c889a669706e3ffc33093e","Warn: containerImage not pinned by hash: supporting-containers/nginx/Dockerfile:7","Warn: containerImage not pinned by hash: supporting-containers/nginx/Dockerfile:58: pin your Docker image by updating nginx:1.19.2 to nginx:1.19.2@sha256:c628b67d21744fce822d22fdcc0389f6bd763daac23a6b77147d0712ea7102d0","Warn: containerImage not pinned by hash: supporting-containers/test-origin/Dockerfile:7: pin your Docker image by updating golang:1.15.0-buster to golang:1.15.0-buster@sha256:eb93d11dc4e39359ecf290c1bfdf18eea125d93f56c889a669706e3ffc33093e","Warn: goCommand not pinned by hash: supporting-containers/test-origin/Dockerfile:9","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   4 containerImage dependencies pinned","Info:   0 out of   1 goCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Vulnerabilities","score":7,"reason":"3 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2021-0052 / GHSA-h395-qcrw-5vmq","Warn: Project is vulnerable to: GHSA-3vp4-m3rf-835h","Warn: Project is vulnerable to: GO-2023-1737 / GHSA-2c4m-59x9-fr2g"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T15:02:16.042Z","repository_id":45969206,"created_at":"2025-08-18T15:02:16.042Z","updated_at":"2025-08-18T15:02:16.042Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29647735,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T09:27:29.698Z","status":"ssl_error","status_checked_at":"2026-02-20T09:26:12.373Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2024-11-09T10:18:26.862Z","updated_at":"2026-02-20T09:32:37.701Z","avatar_url":"https://github.com/equalitie.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Banjax-go\n \n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/equalitie/banjax-next/blob/master/edge-diagram.svg\" alt=\"edge diagram\"\u003e\n\u003c/p\u003e\n\nOur edge architecture at Deflect for many years was Apache Trafficserver and a custom plugin called Banjax. This plugin did some basic rate-limiting on incoming requests according to a configurable set of regex patterns. If a rate-limit was exceeded, we could block further requests from that IP address, or we could serve a challenge-response page (JS-based proof-of-work, or password-based authentication).\n\nBanjax-go is a rewrite of this which performs the same functionality, but as a separate process rather than a plugin. We're also using it with Nginx now instead of Trafficserver, but the idea should work with any reverse proxy that supports X-Accel-Redirect. Instead of doing the regex matching on incoming requests in the Nginx/Trafficserver process, we are tailing access logs similarly to fail2ban.\n\nThe relationship between Nginx and banjax-go is probably best understood with a sample Nginx configuration:\n\n```\n# Nginx forwards incoming requests to banjax-go, which responds with an X-Accel-Redirect header\nlocation / {\n    proxy_pass http://banjax-go/auth_request\n}\n\n# if X-Accel-Redirect is \"@access_granted\", Nginx internally redirects here\nlocation @access_granted {\n    proxy_pass https://origin-server\n}\n\n# likewise if X-Accel-Redirect is \"@access_denied\"\nlocation @access_denied {\n    return 403 \"access denied\";\n}\n```\n\nSome observations:\n* The old plugin-based system was hooking Trafficserver's internal request-processing state machine\n  events. This was quite hard to understand and extend, and the resulting behavior wasn't apparent\n  or changeable in a config file. Leveraging existing higher-level HTTP middleware concepts makes\n  the whole thing easier to understand and modify.\n* We can leverage Nginx's powerful block-based configuration format. Caching the auth request\n  responses, adding timeout and failure-handling behavior, or treating static files specially\n  can all be done in the Nginx config instead of with code.\n\n## Banjax-go's decision-making process\n\nBanjax-go currently has four internal Decision types:\n\n* Allow\n  * returns `X-Accel-Redirect: @access_granted` to Nginx.\n* NginxBlock\n  * returns `X-Accel-Redirect: @access_denied` to Nginx.\n* IptablesBlock\n  * returns `@access_denied` *and also* blocks that IP with iptables.\n* Challenge\n  * returns a JS-based SHA-inverting proof-of-work page. if the request contains\n    a cookie with a solved challenge, banjax-go returns `@access_granted`. if an IP\n    exceeds a rate limit of failed challenges, they get blocked.\n\nThe Decision lists are populated by:\n\n* The config file. This is useful for allowlisting or blocklisting known good or bad IPs.\n* The regex-matching rate-limiting log tailer. Rules specify the regex to look for, the\n  number of hits and time interval that determine the rate limit, and the Decision to\n  take for future requests from that IP if the rate limit is exceeded.\n* A Kafka topic. This is how Baskerville sends its ML-informed commands to Banjax-go.\n* A rate limit on the number of failed challenges an IP submits. Bots will generally\n  fail a bunch of challenges, and we want to block them after a while rather than\n  serve them an unlimited number of challenge pages.\n\nDecisions added at run-time (from the log tailer, Kafka, or the failed challenge rate limit)\nexpire after some configurable amount of time.\n\n[XXX figure out priority levels between the lists and types]\n\n## Password-protected paths\n\nFrom the perspective of the JS and cookie cryptographic implementation, these work very\nsimilarly to the SHA-inverting proof-of-work challenge. But the use-cases are different:\nthe PoW challenge is intended to filter out DDoS traffic, and so it makes sense for the\nNginx configuration to fail open in case Banjax-go is unreachable. Password-protected\npaths should probably fail closed. [XXX does this make sense? there were other distinctions?]\n\n## Sample configuration\n```yaml\nconfig_version: 2020-12-15_12:35:38\nglobal_decision_lists:         # static allow/challenge/block decisions (global)\n  allow:\n  - 20.20.20.20\n  block:\n  - 30.40.50.60\n  challenge:\n  - 8.8.8.8\nper_site_decision_lists:       # static allow/challenge/block decisions (per-site)\n  example.com:\n    allow:\n    - 20.20.20.20\n    block:\n    - 30.40.50.60\n    challenge:\n    - 8.8.8.8\niptables_ban_seconds: 10       # how long an iptables ban lasts\niptables_unbanner_seconds: 5   # how often the unbanning task runs\nkafka_brokers:\n- localhost:9092\npassword_hashes:               # for password_protected_paths\n  example.com: \u003cbase64 string\u003e \npassword_protected_paths:      # for password_protected_paths\n  example.com:\n  - wp-admin\nper_site_rate_limited_regexes: # fail2ban-like challenging/blocking (per-site)\n  example.com:\n  - decision: block\n    hits_per_interval: 10\n    interval: 120\n    name: UNNAMED RULE\n    regex: 'GET \\/search\\/.*'\nregexes_with_rates:            # fail2ban-like challenging/blocking (global)\n- decision: block\n  hits_per_interval: 0\n  interval: 1\n  regex: .*blockme.*\n  rule: instant block\n- decision: challenge\n  hits_per_interval: 0\n  interval: 1\n  regex: .*challengeme.*\n  rule: instant challenge\nserver_log_file: /var/log/banjax-next/banjax-next-format.log  # nginx log file with specific format\n```\n\n---\n\n\u003ca rel=\"license\" href=\"http://creativecommons.org/licenses/by/4.0/\"\u003e\n\u003cimg alt=\"Creative Commons Licence\" style=\"border-width:0\" src=\"https://i.creativecommons.org/l/by/4.0/80x15.png\" /\u003e\u003c/a\u003e\u003cbr /\u003e\nThis work is copyright (c) 2020, eQualit.ie inc., and is licensed under a \u003ca rel=\"license\" href=\"http://creativecommons.org/licenses/by/4.0/\"\u003eCreative Commons Attribution 4.0 International License\u003c/a\u003e.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fequalitie%2Fbanjax-next","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fequalitie%2Fbanjax-next","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fequalitie%2Fbanjax-next/lists"}