Skip to content

Sync/upstream 2026 07#11

Merged
Che4ter merged 124 commits into
bv-developfrom
sync/upstream-2026-07
Jul 7, 2026
Merged

Sync/upstream 2026 07#11
Che4ter merged 124 commits into
bv-developfrom
sync/upstream-2026-07

Conversation

@Che4ter

@Che4ter Che4ter commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator
  • Sync the latest upstream changes

fatpeppapig and others added 30 commits May 22, 2026 14:54
[FIX] Fixed order of authentication methods for timeline filter endpoint.
…se-access, customers, audit, MFA reset and API-key rotation
…solutions, analysis statuses, event categories and task statuses
…e PUT and POST backup, deprecating the legacy /manage/settings routes
… credentials from user schemas and marking sensitive fields load-only

Backport of f1d41f4 from v2.4.29. UserSchema, UserFullSchema, and
BasicUserSchema were leaking mfa_secrets and webauthn_credentials in
serialized responses, letting an attacker bypass MFA or impersonate
the user (CWE-201, SBA-ADV-20260126-04). user_password is now load-only
on UserSchema, and DSFileSchema.file_local_name (server-side path) is
declared load-only at the schema layer instead of being del'd in the
route handler.

The matching v2 schema (UserSchemaForAPIV2) already had these guards;
this commit aligns the legacy schemas still in use.
…er, profile and taxonomy admin endpoints

Backport of f84b7b9 from v2.4.29, extended to cover the v2 surface
that didn't exist when the original fix shipped.

The legacy /manage/users, /manage/asset-type, /manage/ioc-types,
/profile/update endpoints accepted the raw request body and handed it
straight to the marshmallow schema. The schemas' `unknown = EXCLUDE`
drops unknown keys but every declared field on the schema is still
accepted — so a caller could overwrite the primary key (mass-assignment
of asset_id / type_id), self-promote to admin via user_isadmin on the
profile endpoint, or set arbitrary attributes the GUI never exposes
(SBA-ADV-20260128-01 / CWE-915).

Each writable endpoint now goes through an explicit per-resource
allowlist before the schema is loaded. The taxonomy CRUD on
rest/v2/manage_routes/case_objects.py declares the allowlist on the
shared TaxonomyConfig so the asset-type, ioc-type, classification,
state and evidence-type sub-blueprints all inherit the protection
without duplication.

GHSA-g588 already made user_password load_only on UserSchema, so the
legacy /manage/users/add no longer needs the `del udata['user_password']`
guard either; remove it.
… allowlist

Backport of 371c640 from v2.4.29, adapted to develop's _is_safe_url
in business/auth.py.

The previous check only verified that urlparse(target).scheme and
urlparse(target).netloc were empty. urlparse treats `attacker.com?cid=1`
as a path with an empty netloc, so the guard accepted attacker-controlled
hosts; browsers resolving the resulting `Location: attacker.com` header
route the user to the attacker's origin (CWE-601 / SBA-ADV-20260126-02).

_is_safe_url now requires the target to be a non-empty string starting
with a single `/` (rejecting both protocol-relative `//evil.com` and
backslash variants like `/\\evil.com`) and free of control characters,
with the urlparse check kept as defense in depth.
…TASTORE_PATH and allowlisting writable upload fields

Backport of 57c1b80 from v2.4.29, extended to the v2 datastore route
that didn't exist when the original fix shipped.

datastore_delete_file and datastore_get_local_file_path now resolve the
recorded file_local_name and refuse to operate on a path outside the
configured DATASTORE_PATH. Even though the dsf row is legitimately
fetched through (file_id, case_id), a stored path pointing elsewhere
(stale row from a different mount, attacker-seeded value) would let an
unlink or send_file escape the datastore — CWE-22.

The legacy /datastore/file/add + /datastore/file/update routes and the
v2 add_file + update_file methods now project the multipart form down
to an allowlist before the schema is loaded, blocking mass-assignment
of file_id, file_local_name, file_case_id, file_sha256, file_size,
added_by_user_id, file_date_added and friends.
…requiring POST on logout

Backport of b202f54 from v2.4.29, extended to cover the v2 alerts
update endpoint that didn't exist when the original fix shipped.

Alert update (legacy single + batch, and v2 PUT /alerts/<id>) now
strips alert_id, alert_customer_id and alert_creation_time from the
payload before the schema is loaded. Allowing those via the API let a
user with write access to one customer re-attribute an alert to a
customer they cannot see — silently hiding it from the rightful owner
and planting it under another tenant's view (CWE-863 /
SBA-ADV-20260128-05).

The logout endpoint moves from GET to POST. A plain <img src="/logout">
on a third-party page would otherwise log the user out without consent
(RFC 7231 §4.2.1: GET must be safe; CWE-650 / SBA-ADV-20260128-03). The
sidenav link wraps a hidden form so existing accessibility / styling
keeps working.
whitekernel and others added 29 commits July 1, 2026 19:40
…IRIS_HOSTNAME single-source-of-truth, certbot deploy-hook
…service + hook listeners + /api/v2/notifications endpoints + /notifications SocketIO namespace + /users/mentionable directory for analyst mention search
…nt/both target, deploy-to-existing) + incident-rules with nested AND/OR conditions, back-fill, JSONB path support (alert_context.foo.bar)
…igation-flows (getters/list/create/update/deploy/backfill), server-owned rule_created_by/flow_created_by attribution, public proxies for cross-module access-control helpers
…ident-statuses endpoint, escalate crash fix
…and detect stopped iriswebapp_db container
… add war_room_id scoping and /_diag notifications endpoint
…r and multi-GB datastore uploads aren't truncated
…_room relationship that broke gunicorn boot (WarRoom unresolvable at mapper-config time)
…c gap

- Add merge migration for the second alembic head introduced by the
  upstream sync (war_room_id_to_user_activity vs our prior merge point).
- Import WarRoom explicitly in models.py so it's registered in the
  declarative registry before UserActivity.war_room is mapper-configured
  (was crashing gunicorn boot with an unresolvable relationship).
- Add worker-src 'self' blob: to the CSP header so Ace editor's
  syntax-highlighting web worker (blob: URL) isn't blocked.
…26-07

# Conflicts:
#	source/requirements.txt
user_activity.war_room_id had no ON DELETE behavior, so Postgres
blocked deleting any war room with logged activity against it — which
is every real war room, since creating one is itself logged. The
existing war_room_delete() code already assumed the FK would go NULL
(see its comment), it just wasn't configured that way at the DB level.
The auto-merge kept both our and upstream's copies of two blocks that
should have collapsed into one: the MFA brute-force lockout helpers in
login_routes.py (plus a duplicate `import time`), and the alert-update
readonly-fields guard in alerts_routes.py. Functionally harmless since
Python just re-defines the same names, but confusing and worth
cleaning up. Kept the better-commented (upstream) copy in each case;
verified py_compile and a container boot after each removal.
… port 443

Running as www-data (re-added in bc6f071 for hardening) blocks binding to
privileged ports without this capability, causing the container to exit
immediately whenever INTERFACE_HTTPS_PORT is left at its default 443 (as
in .env.tests.model) instead of a dev override like 8443. This broke the
Test API, Database migration tests, and End to end tests CI jobs, which
all depend on the nginx container starting successfully.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- business/auth.py: remove duplicate `import time` left by the 3-way
  merge (same pattern already fixed in login_routes.py/alerts_routes.py)
- access_control/utils.py, alembic/versions/e5d79b8c4a55_...py: drop
  stray extra blank lines left where overlapping merge hunks joined

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cleans up ruff UP032 findings in our own docx report generation code
(not present upstream). Report generation tests still pass.
/collab/ used a static proxy_pass to "collab", resolved at nginx
startup. CI's docker-compose.dev.yml (upstream's own file) has no
collab service, so nginx refused to start at all:
  nginx: [emerg] host not found in upstream "collab"

Switch to a variable + Docker's embedded resolver so DNS is resolved
per-request instead. nginx now starts fine without collab present;
only requests to /collab/ fail if it's genuinely absent, which is
correct since it's an optional BV-only feature.

Verified locally: nginx stays up with collab stopped, and successfully
proxies through to it once collab is running again.
@Che4ter Che4ter merged commit ce0895d into bv-develop Jul 7, 2026
10 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants