Files
Open_Ultra_SAST/benchmarks/independent/research-2026-09-24.md
T
Marius CiepluchandClaude Opus 5.5 451d4e4be7 spec(pre-push-safety-net): reserve the independent population v1 (15.1), unscanned
Eleven cases chosen by the maintainer from fifteen researched by advisory
and fix diff only -- nothing cloned, nothing scanned, none among the 262
repositories the benchmarks reference -- plus the earlier Ghost
reservation. Four are PHP repositories that ship JavaScript (two WordPress
plugins), satisfying the multi-language requirement; families are limited
to the v1 scope (injection, untrusted destination, permissive config).

The development subjects shaped every rule of the last week and can no
longer measure whether those rules generalise; this population can, until
something scans it. A guard test fails the moment a reserved repository is
referenced by a recipe, catalog, manifest or measurement outside
benchmarks/independent/. Freezing (pins and sinks verified by reading
source, a benign change per case) is the next step.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
2026-09-24 16:12:22 +02:00

24 KiB
Raw Blame History

Independent evaluation population: candidate real-world cases

Research date: 2026-09-24. Selected by the maintainer: 11 of these 15 (see population-v1.toml); not selected: The Events Calendar, Tutor LMS, pyLoad, unfurl. Method: web research only. I read GitHub advisories (GHSA/CVE), commit pages, compare views and diffs through the GitHub REST API (gh api) and the web. I did not clone any repository or run any scanner or project tooling.

Exclusion check: I compared every repo URL below against used-repos.txt (case-insensitive exact match on https://github.com/<owner>/<repo>). None of them is on the list. None is NodeGoat, VAmPI, PMPro, WP Statistics, MW WP Form, libpng, a deliberately vulnerable training app or a benchmark suite. I did not use Ghost.

"Diff seen" means I read the patch hunks of the named fix commit through the GitHub API. "Vuln" is the parent of the fix commit unless a tag is given. Tags come with the commit SHA they resolve to.

Summary table

# id repo lang family advisory vulnerable (commit / tag) fixed (commit / tag) sink file :: function privilege diff seen
1 wp-ultimate-member-sqli https://github.com/ultimatemember/ultimatemember PHP+JS (WP plugin) SQLi CVE-2024-1071 / GHSA-mh7h-gpmx-fggj tag 2.8.2 = e1885a73a8ad542cfd2ed60aef38a6bce4ab8553; commit-level parent a49b3061ded1630e4f6860b4ebece5ccf0a493d2 476de92f4c9aaa56c3e2f5527b242ce0476f4655 (+ c61008bdbe1ce8de4597b41c7aad8dfda88f527d); tag 2.8.3 = a6a7d13a433b24e468ee10e778e3da5668b6ef59 includes/core/class-member-directory-meta.php :: Member_Directory_Meta::ajax_get_members() ($this->sql_order ORDER BY) unauthenticated yes
2 wp-learnpress-sqli https://github.com/LearnPress/learnpress PHP+JS (WP plugin) SQLi CVE-2024-8522 / GHSA-3w3r-r6g6-w8x5 (+ CVE-2024-8529 / GHSA-98wp-w76v-f75p) 73b3cbceef8669056e9da5e2f2c78944eb139af5 (4.2.7) aaf42fe0c6bf05dcf2ff125750b7bd836e76fa3c (4.2.7.1) inc/Databases/class-lp-db.php :: LP_Database::execute() (implode(',', $filter->only_fields) into SELECT); source inc/jwt/rest-api/version1/class-lp-rest-courses-v1-controller.php :: get_courses() unauthenticated (REST /wp-json/learnpress/v1/courses) yes
3 wp-events-calendar-sqli https://github.com/the-events-calendar/the-events-calendar PHP+JS (WP plugin) SQLi CVE-2024-8275 / GHSA-v6x4-m48j-jm68 tag 6.6.4 = 4e4baa3fee7ef49abdd4cb277d963d555ffab4c7 tag 6.6.4.1 = 419965a87d99195ad3fca22738e19dd287051f1c (fix hunk in e128ec5e2a25fe4fdc4542a9023918bf915b4084) src/Events/Custom_Tables/V1/WP_Query/Custom_Tables_Query.php :: redirect_posts_orderby() / parse_orderby() unauthenticated per Wordfence (reached through tribe_has_next_event order) yes
4 wp-tutor-lms-coupon-sqli https://github.com/themeum/tutor PHP+JS/TS (WP plugin) SQLi CVE-2025-13673 / GHSA-f7q9-gg7h-5rff tag v3.9.6 = 71187a525dbdbdb045137af702307f05dda6a7a6 (= parent of fix) e4a25f69f0fb63a46d57eff6ba5b58378a4c088d (3.9.7, no GitHub tag) helpers/QueryHelper.php :: prepare_where_clause() / make_clause(); source models/CouponModel.php :: get_coupon_details_for_checkout(), get_coupon_by_code() unauthenticated (checkout coupon_code) yes (mapping partly inferred)
5 phpmyfaq-captcha-ua-sqli https://github.com/thorsten/phpMyFAQ PHP+TS/JS SQLi CVE-2026-46364 / GHSA-289f-fq7w-6q2w 11583abcf4787543d00c25d6c7926af6f509faf0; tag 4.1.1 = f791858b2aa4b811f5b19d10c20ba5c4a30786de 545bdffb11244a4741cd29ac909a849c9a6a2e53; tag 4.1.2 = 66792f2575b07d65896b504d47deb5f4f903f9ff phpmyfaq/src/phpMyFAQ/Captcha/BuiltinCaptcha.php :: garbageCollector(), saveCaptcha() unauthenticated (GET /api/captcha, User-Agent header) yes
6 yeswiki-bazar-form-sqli https://github.com/YesWiki/yeswiki PHP+JS SQLi CVE-2026-46670 / GHSA-jwvv-qr7q-cv8j 6f222915df36fca628fc83325cb0feed8dc2aca0; tag v4.6.3 = 5e8fc114d01d558dc4799b95219549ccf02ebd11 fe7244bffcbeffd42777496ebc2a6f6118cc2388; tag v4.6.4 = c1bae9fc260eb3e4346f3b0bc65ab609d1cf783a tools/bazar/services/FormManager.php :: FormManager::create(); source tools/bazar/controllers/FormController.php :: displayAll() unauthenticated yes
7 signalk-remote-conn-ssrf https://github.com/SignalK/signalk-server TypeScript (Node/Express) SSRF CVE-2026-55591 / GHSA-q59x-jc9f-gfqf 1c479cc0d2d26d14ed74416cff36fa7336c7bf9e; tag v2.27.0 = 4592992aaf7c44548842be9390b651cfb816eaf4 2816b0dda1bdde893d85c969a9c5950e7825eee7; tag v2.28.0 = 3645160b235364e1fd3afe1f2f6b2270b8194b7d src/serverroutes.ts :: makeRemoteRequest() (from testSignalKConnection, requestAccess, checkAccessRequest routes) unauthenticated by default (security not configured); admin otherwise yes
8 saltcorn-sync-sqli https://github.com/saltcorn/saltcorn JavaScript/TS (Node/Express) SQLi CVE-2026-41478 / GHSA-jp74-mfrx-3qvh e7e09254a3c69dc6582eda9e5b5769935db108af; tag v1.4.5 = 92d24ca5ce8480d3b0cf1067e33113f2a790030c 2b6c8a2eab88955ea6b12b1b4e5c2e613faefef5; tag v1.4.6 = d49e6a947de777053a203a27ab4d9e1a1754ccd0 (backport) packages/server/routes/sync.js :: getSyncRows(), getDelRows() (+ packages/saltcorn-data/models/table.ts sync_info queries) authenticated low-privilege user yes
9 mongo-express-bson-rce https://github.com/mongo-express/mongo-express JavaScript (Node/Express) code injection (vm eval) CVE-2019-10758 / GHSA-h47j-hc6x-h3qq ea02b364d43f179f191fc91fb9962efdb0843a8d; tag v0.53.0 = 9eb49994f3842260f7c6db75592ea6ba9376fad6 d8c9bda46a204ecba1d35558452685cd0674e6f2; tag v0.54.0 = 7d365141deadbd38fa961cd835ce68eab5731494 lib/bson.js :: toBSON() (vm.runInNewContext over request text); callers lib/routes/collection.js, lib/routes/document.js authenticated (HTTP basic auth, default admin:pass) yes
10 mockoon-admin-api-cors https://github.com/mockoon/mockoon TypeScript (Node/Express) permissive CORS CVE-2026-59148 / GHSA-rqx4-3f6q-3x2v b42bdfb7f82e83f0e81bea8e6fe41adf5ec82585; tag v9.6.1 = 1c874584c058b891f6affbb44d5a5223f3f8f812 c420b5a56918475b8663977b51e5f986e45b3299; tag v9.7.0 = df02ba3b0d9e8b88651230f3b38d8e6fa3679b9b packages/commons-server/src/libs/server/admin-api.ts :: admin-API middleware (app.use(${adminApiPrefix}*), Access-Control-Allow-Origin: *) unauthenticated yes (large diff, one CORS hunk)
11 pyload-add-package-sqli https://github.com/pyload/pyload Python (Flask) SQLi CVE-2025-55156 / GHSA-pwh4-6r3m-j2rf a123accec0618798db77f9f5bc66838b741d9f58 134edcdf6e2a10c393743c254da3d9d90b74258f (0.5.0b3.dev91) src/pyload/core/database/file_database.py :: FileDatabaseMethods.update_link_info(); source src/pyload/webui/app/blueprints/json_blueprint.py :: add_package authenticated (ADD permission) yes
12 alerta-query-sqli https://github.com/alerta/alerta Python (Flask) SQLi CVE-2026-34400 / GHSA-8prr-286p-4w7j 71c098d8bb8091e76edaefeef4662eb77c753ce7; tag v9.0.4 = b7111d23ae9aefb5064ef107976f62e3836217b6 fdd52cd1abad8d02d1dfb8ecdcdbb43b6af3b883; tag v9.1.0 = f4312727783dad64198b62ed778bbca98a5144a3 alerta/database/backends/postgres/queryparser.py :: SearchTerm.__repr__ (f-string WHERE); used by alerta/database/backends/postgres/utils.py :: QueryBuilder.from_params() API user (API key when AUTH_REQUIRED; see notes) yes
13 wger-next-open-redirect https://github.com/wger-project/wger Python (Django) open redirect GHSA-vqv8-j3mj-wjxj (no CVE) d30e85b23fb1307ac6579e9e3ae393c50470cea7; tag 2.5 = c1fca6bdf77d8ed80048d1b73a8da80cf36ee751 0ba371bbb50cd5668820f240995405e1b2483384; tag 2.6 = e1d70bcc38cd56ae4a254dca1713c404d069f319 wger/core/views/user.py :: trainer_login(); wger/core/views/languages.py :: use_browser_language() use_browser_language: unauthenticated; trainer_login: authenticated trainer yes
14 unfurl-flask-debug https://github.com/obsidianforensics/unfurl Python (Flask) permissive config (debug on) GHSA-vg9h-jx4v-cwx2 (no CVE) 6b8e97853090c909936a18d41228168b7a35fe94 4c0a07ab1e9af3a1ddf0e7f47153ec9ba77946dd unfurl/app.py :: web_app() → UnfurlApp.__init__ app.run(debug=...) unauthenticated (Werkzeug debugger) yes
15 opencve-notification-ssrf https://github.com/opencve/opencve Python (Django) SSRF CVE-2026-62282 / GHSA-ch3g-4xvr-674q 928bbadbb1672051bcfc2a6289a9e6a8f029c106 0af7f894debc95c67fa53e7ba5a6cdecb10c34f0; tag v3.0.0 = 928943aa87ceac789061114159d74c2067cc6ae6 web/projects/notifications.py :: _http_post_json() (webhook and Slack test); forms in web/projects/forms.py authenticated (can configure project notifications) yes

Mix: 6 PHP (all six repos ship JS, four are WordPress plugins), 4 JS/TS, 5 Python. By family: 10 injection (9 SQLi: #1–6, #8, #11, #12; 1 code injection: #9), 3 untrusted destination (SSRF #7 and #15, open redirect #13), 2 permissive configuration (CORS #10, debug #14). By privilege: 10 unauthenticated or unauthenticated by default (#1–7, #10, #14, plus #13's use_browser_language sink) and 5 authenticated (#8, #9, #11, #15, and #12 depending on AUTH_REQUIRED).

Per-candidate notes

1. wp-ultimate-member-sqli (PHP+JS, WordPress)

  • Repo: https://github.com/ultimatemember/ultimatemember (GPL, PHP 2.7 MB + JS 0.6 MB).
  • Advisory: CVE-2024-1071, GHSA-mh7h-gpmx-fggj (unreviewed GHSA mirror of the Wordfence record). Affects 2.1.3–2.8.2, CVSS 9.8.
  • Flaw: ajax_get_members() builds $this->sql_order = " ORDER BY CAST(umm_sort.um_value AS {$custom_sort_type}) {$custom_sort_order} " and similar ORDER BY strings. Values from the member-directory sorting request pass only through esc_sql(). That does not protect a context without quotes. Only exploitable when the "custom usermeta table" option is on.
  • Fix: 476de92f checks $order / $custom_sort_order against ASC/DESC and $custom_sort_type against $this->sort_data_types. c61008bd ("fixed security issue with mysql query escape") is a larger WPCS refactor of the same file. Use 476de92f as the minimal fix and the 2.8.2 → 2.8.3 tags for a release-level pair.
  • Confidence: high. I read both diffs. The 2.8.2...2.8.3 compare has 94 commits, so a tag pair gives a noisy diff. The commit pair is cleaner.

2. wp-learnpress-sqli (PHP+JS, WordPress)

  • Repo: https://github.com/LearnPress/learnpress (PHP 5.9 MB, JS 1.4 MB).
  • Advisories: CVE-2024-8522 (c_only_fields, CVSS 10.0) and CVE-2024-8529 (c_fields). Both are fixed by the same commit.
  • Flaw: the REST controller get_courses() put explode(',', $params['c_only_fields']) straight into $filter->only_fields. LP_Database::execute() then runs implode(',', array_unique($filter->only_fields)) into the SELECT column list (class-lp-db.php around line 607).
  • Fix aaf42fe0: Courses::handle_params_for_query_courses() now runs every field through $wpdb->prepare('%i', $field) (identifier quoting), and the controller's direct assignment is removed. It also touches assets/src/js/loadAJAX.js, so the commit is itself multi-language.
  • Confidence: high. I read the diff and checked the sink line at the vulnerable commit.

3. wp-events-calendar-sqli (PHP+JS, WordPress)

  • Repo: https://github.com/the-events-calendar/the-events-calendar (large plugin: PHP 10 MB, JS 0.7 MB; license field NOASSERTION, the plugin is GPL). It has a git submodule common (tribe-common), so a checkout needs --recursive.
  • Advisory: CVE-2024-8275, GHSA-v6x4-m48j-jm68. The order parameter of tribe_has_next_event, ≤ 6.6.4.
  • Flaw: redirect_posts_orderby() split ORDER BY fragments with a regex and kept any trailing order token as is. parse_orderby() inserted $order into "ID $order, ...".
  • Fix (6.6.4.1, commit e128ec5e): adds sanitize_order() (only ASC/DESC) and applies it at both sites. It also bumps the submodule.
  • Privilege: Wordfence rates it unauthenticated. Reachability in practice depends on how the template tag's arguments reach WP_Query. The ground-truth sink is still unambiguous.
  • Confidence: high for the diff. Medium for how exploitable it is from a clean install.

4. wp-tutor-lms-coupon-sqli (PHP+JS/TS, WordPress)

  • Repo: https://github.com/themeum/tutor (GPL-3.0; PHP 3.8 MB, TS 3.3 MB, JS 0.4 MB).
  • Advisory: CVE-2025-13673, GHSA-f7q9-gg7h-5rff. ≤ 3.9.6, unauthenticated coupon_code. Partial fixes shipped in 3.9.4 and 3.9.6.
  • Flaw: QueryHelper::prepare_where_clause() built values as "'" . $val . "'". The only escaping was an esc_sql() in get_coupon_details_for_checkout(). Other coupon paths (get_coupon_by_code(), get_coupon_usage_count(), get_coupon_applications()) pass $coupon_code through without escaping.
  • Fix e4a25f69 (parent = tag v3.9.6): make_clause() now binds every value through $wpdb->prepare('%s'|'%d', ...), and the manual quoting and esc_sql are removed.
  • Confidence: medium. I read the diff and it is the only SQL change right after v3.9.6. The trac changeset cited by the CVE (3469242) returned 403, so the exact exploited call chain from the checkout request to QueryHelper is my inference. There is no v3.9.7 tag on GitHub. Use the commit pair.

5. phpmyfaq-captcha-ua-sqli (PHP+TS/JS)

  • Repo: https://github.com/thorsten/phpMyFAQ (MPL-2.0; PHP 14.7 MB, TS 1.7 MB).
  • Advisory: CVE-2026-46364, GHSA-289f-fq7w-6q2w. ≤ 4.1.1. The advisory's commit reference b9f25109 is the vulnerable master commit the reporter tested, not the fix.
  • Flaw: the constructor stores $request->headers->get('user-agent') and getClientIp(). garbageCollector() (DELETE) and saveCaptcha() (SELECT/INSERT) put them into sprintf SQL without escaping. Both run on every GET /api/captcha.
  • Fix 545bdffb ("fix: added missing escaping"): adds escapeQueryValue() for userAgent, ip, language and code.
  • Confidence: high. I read the diff in the 4.1.1...4.1.2 compare and the commit.

6. yeswiki-bazar-form-sqli (PHP+JS)

  • Repo: https://github.com/YesWiki/yeswiki (AGPL-3.0; PHP 4 MB, JS 0.8 MB). Default branch doryphore-dev.
  • Advisory: CVE-2026-46670, GHSA-jwvv-qr7q-cv8j. < 4.6.4.
  • Flaw: FormManager::create() concatenates $data['bn_id_nature'] unquoted into INSERT ... VALUES (. The data comes from $_POST['imported-form'] JSON in FormController::displayAll(), and that path had no permission check.
  • Fix fe7244bf: intval($data['bn_id_nature']) plus a Guard::isAllowed('saisie_formulaire') check. The diff is 4 lines.
  • Confidence: high. I read the diff. Related YesWiki SQLi advisories (GHSA-qg78-vmvc-fhjw, GHSA-f58v-p6j9-24c2, GHSA-4pf7-cc4r-g63h) could add more cases from the same repo.

7. signalk-remote-conn-ssrf (TypeScript, Node/Express)

  • Repo: https://github.com/SignalK/signalk-server (Apache-2.0, about 24 MB).
  • Advisory: CVE-2026-55591, GHSA-q59x-jc9f-gfqf. ≤ 2.27.0.
  • Flaw: makeRemoteRequest(host, port, useTLS, selfsignedcert, path) passes req.body.host/port to http(s).request without validation. It is reached from three admin routes.
  • Fix 2816b0dd: TypeBox schema validation (new src/remoteConnectionSchemas.ts), a new src/ssrfGuard.ts (BlockList for loopback, link-local and metadata, plus a DNS lookup guard) wired into makeRemoteRequest, and UUID validation of requestId.
  • Confidence: high. I read the diff. It is medium-sized, about 450 added lines, mostly new guard code and tests.

8. saltcorn-sync-sqli (JavaScript/TS, Node/Express)

  • Repo: https://github.com/saltcorn/saltcorn (MIT). It is a monorepo of packages and on the large side (about 340 MB of git data), but the relevant code is in packages/server and packages/saltcorn-data.
  • Advisory: CVE-2026-41478, GHSA-jp74-mfrx-3qvh. < 1.4.6 / < 1.5.6 / < 1.6.0-beta.5.
  • Flaw: getSyncRows() interpolates ${syncInfo.maxLoadedId} (from req.body.syncInfos[table].maxLoadedId) and ${user.id} into SQL template literals. getDelRows() does the same with timestamps.
  • Fix 2b6c8a2e: integer and date validation plus $1-style parameterised queries in sync.js and table.ts.
  • Confidence: high. I read the diff. The fix commit is on the main line, and v1.4.6 is a separate backport. For a clean pair, use the commit and its parent e7e09254.

9. mongo-express-bson-rce (JavaScript, Node/Express)

  • Repo: https://github.com/mongo-express/mongo-express (MIT, about 16 MB).
  • Advisory: CVE-2019-10758, GHSA-h47j-hc6x-h3qq (CWE-94/78). < 0.54.0.
  • Flaw: lib/bson.js toBSON() evaluates user-supplied document/query text with vm.runInNewContext in a BSON sandbox. The sandbox can be escaped, which gives RCE through the /checkValid and document/collection routes.
  • Fix d8c9bda4: replaces the vm-based parser with mongodb-query-parser. It removes 101 lines from bson.js, deletes lib/json.js and changes collection.js.
  • Confidence: high. I read the diff. It is an older case (2019), useful as a known-answer eval sink. Note that the advisory's first reference, 7d365141, is only the version-bump or release commit (= tag v0.54.0).

10. mockoon-admin-api-cors (TypeScript, Node/Express)

  • Repo: https://github.com/mockoon/mockoon (MIT; monorepo of app, cli, commons-server and serverless; about 42 MB).
  • Advisory: CVE-2026-59148, GHSA-rqx4-3f6q-3x2v (CWE-942/306/352/732). < 9.7.0.
  • Flaw: the admin API middleware sets Access-Control-Allow-Origin: * with all methods on every /mockoon-admin/* endpoint. The admin API is on by default and has no authentication.
  • Fix c420b5a5: adds a configurable adminApiCorsOrigins allowlist (no header by default, 403 on preflight), optional admin API auth, and an env-var prefix check.
  • Confidence: high that the CORS hunk is the fix. The commit is large (34 files), but the permissive-CORS sink sits in one clearly identifiable hunk of admin-api.ts. It is a weaker fit for "small diff" than the others.

11. pyload-add-package-sqli (Python, Flask)

  • Repo: https://github.com/pyload/pyload (AGPL-3.0, GitHub reports NOASSERTION; about 50 MB).
  • Advisory: CVE-2025-55156, GHSA-pwh4-6r3m-j2rf. < 0.5.0b3.dev91.
  • Flaw: update_link_info() builds "','".join(x[3] for x in data) into f"SELECT id FROM links WHERE url IN ('{statuses}')". The URLs come from add_links on /json/add_package. Chain: json_blueprint add_package → Api.add_package → FileManager.add_links → InfoThread → update_file_info → update_link_info.
  • Fix 134edcdf: ? placeholders. The diff is 5 lines. The source-to-sink path crosses a thread, which makes it a good cross-thread taint test.
  • Confidence: high. I read the diff. The same repo also has CVE-2023-0297 (GHSA-pf38-5p22-x6h6, unauthenticated js2py code injection, fix 7d73ba7919e594d783b3411d7ddb87885aea782d, parent 6aa71cd99a6f510de7137d17ec99f930916704c0). I kept it as an alternate only, because that fix just calls js2py.disable_pyimport(). The eval_js sink stays in the fixed tree, so a sink-based analyzer would still correctly flag the fixed version.

12. alerta-query-sqli (Python, Flask)

  • Repo: https://github.com/alerta/alerta (Apache-2.0, about 11 MB).
  • Advisory: CVE-2026-34400, GHSA-8prr-286p-4w7j. < 9.1.0. The advisory's aeba85a3 reference (2018) is the commit that introduced the parser. The fix is fdd52cd1.
  • Flaw: the Postgres query-string parser (?q=) turned parsed search terms into SQL with f-strings in SearchTerm.__repr__. QueryBuilder.from_params() then used that as a WHERE clause with an empty qvars.
  • Fix: new to_sql(params) methods produce %(name)s placeholders, and from_params() passes the parsed vars.
  • Privilege: alerta requires an API key or login when AUTH_REQUIRED=True. I believe the default is False, which would make this unauthenticated on a default install, but I did not check settings.py. Record it as "API user, possibly unauthenticated".
  • Confidence: high for the diff. The fix is about 100 lines in one file plus tests.

13. wger-next-open-redirect (Python, Django)

  • Repo: https://github.com/wger-project/wger (AGPL-3.0, about 91 MB with a JS frontend).
  • Advisory: GHSA-vqv8-j3mj-wjxj (no CVE assigned). ≤ 2.5, fixed in 2.6.
  • Flaw: trainer_login() returns HttpResponseRedirect(request.GET['next']). use_browser_language() redirects to remove_language_code(request.GET.get('next','/')). Neither checks host or scheme.
  • Fix 0ba371bb: url_has_allowed_host_and_scheme() at both sites. The diff is 20 lines of code plus tests.
  • Two sinks, two privilege levels: use_browser_language is unauthenticated, trainer_login needs a trainer. A later follow-up, cfa27a7fc78c682ad4244020505dce4825fe1e26, fixes the same pattern in wger/core/middleware.py (AuthProxyMiddleware). I found no separate advisory for it. It is optional as a third sink, but it is not in the 2.6 fix.
  • Confidence: high. I read the diff.

14. unfurl-flask-debug (Python, Flask)

  • Repo: https://github.com/obsidianforensics/unfurl (Apache-2.0, about 24 MB).
  • Advisory: GHSA-vg9h-jx4v-cwx2 (critical, CWE-489, no CVE). The GHSA lists "patched: none" as a package version, but it references the fix commit.
  • Flaw: web_app() reads debug with config[...].get('debug'), which returns a string. Any non-empty string, including "False", is truthy, so app.run(debug=...) always enables the Werkzeug debugger.
  • Fix 4c0a07ab: getboolean('debug') and debug = false in unfurl.ini. The diff is 2 lines.
  • Caveat: the function default debug='True' is unchanged in the fixed version, so a run without an [UNFURL_APP] section still starts in debug mode. The fixed revision may therefore still, correctly, be flagged for debug-on by a strict analyzer.
  • Confidence: high. I read the diff.

15. opencve-notification-ssrf (Python, Django)

  • Repo: https://github.com/opencve/opencve (GitHub license: NOASSERTION. I believe OpenCVE v2+ is under a non-OSI license (BSL), but I did not verify this. Check before use).
  • Advisory: CVE-2026-62282, GHSA-ch3g-4xvr-674q. The advisory's version ranges are confusing ("≤ 1.5.0, patched 3.0.0"). Use the commit pair.
  • Flaw: webhook and Slack notification "test" requests POST to a user-supplied URL (_http_post_json with urllib) and do not restrict the destination.
  • Fix 0af7f894: new web/opencve/utils/ssrf.py (validate_public_http_url, safe_request with DNS pinning), clean_url/clean_webhook_url validators in forms.py, and notifications.py switched to safe_request.
  • Confidence: high for the diff. The license is the concern. It is the weakest Python pick; drop it if an OSS license is mandatory.

Considered and rejected (for traceability)

  • vantage6 CVE-2024-23823 (permissive CORS, fix 70bb4e1d889230a841eb364d6c03accd7dd01a41): the fix only adds a cors_allowed_origins option whose default is still "*", so the fixed version is still permissive by default.
  • FlaskBB CVE-2026-46556 (SSRF): the advisory has no patched version. The only related commit (e87e585f) just sets allow_redirects=False.
  • SillyTavern CVE-2026-46372 (SSRF): the fix is a global request filter that is off by default.
  • NodeBB CVE-2025-50979 (SQLi): no patched version or fix commit is listed, and I could not confirm the claim.
  • Etherpad CVE-2026-55087 (open redirect): the referenced commits introduced the code. The fix is inside a large "assorted hardening" PR (#7784).
  • EverShop CVE-2023-46943 (hardcoded HMAC secret): the fix is a large dev→main merge commit.
  • claude-code-router CVE-2025-57755 (CORS): no tags, and I found no identifiable fix commit.
  • calibre-web CVE-2022-0339 (SSRF): the fix commit is mixed with unrelated Kobo-sync changes. calibre-web SQLi CVE-2022-30765 (GHSA-8ppf-x4gr-2x7g) could be a Python alternate, but I did not check its diff.
  • Tutor LMS PRs #3011/#3014/#3018 (SQLi hardening, Sept 2026): no CVE linked yet.