Summary
update_household issues UPDATE household SET ... WHERE id = ? without scoping to country_id. Because household IDs are not partitioned per country, a valid PUT from one country can silently overwrite a row that actually belongs to another country — most visibly corrupting api_version to the wrong country's package version.
Location
policyengine_api/services/household_service.py:110-119
What goes wrong
household_hash: str = hash_object(household_json)
api_version: str = COUNTRY_PACKAGE_VERSIONS.get(country_id)
database.query(
f"UPDATE household SET household_json = ?, household_hash = ?, label = ?, api_version = ? WHERE id = ?",
(
json.dumps(household_json),
household_hash,
label,
api_version,
household_id,
),
)
If a caller PUTs /uk/household/<id> where <id> is actually a us row, the row is rewritten with api_version from COUNTRY_PACKAGE_VERSIONS["uk"]. Subsequent reads that assume country_id matching will return inconsistent data.
Suggested fix
Add the country predicate to WHERE, and verify the update affected exactly one row before returning success:
result = database.query(
"UPDATE household SET household_json = ?, household_hash = ?, label = ?, api_version = ? "
"WHERE id = ? AND country_id = ?",
(
json.dumps(household_json),
household_hash,
label,
api_version,
household_id,
country_id,
),
)
# raise NotFound if 0 rows updated
Severity
High.
Summary
update_householdissuesUPDATE household SET ... WHERE id = ?without scoping tocountry_id. Because household IDs are not partitioned per country, a valid PUT from one country can silently overwrite a row that actually belongs to another country — most visibly corruptingapi_versionto the wrong country's package version.Location
policyengine_api/services/household_service.py:110-119What goes wrong
If a caller PUTs
/uk/household/<id>where<id>is actually ausrow, the row is rewritten withapi_versionfromCOUNTRY_PACKAGE_VERSIONS["uk"]. Subsequent reads that assumecountry_idmatching will return inconsistent data.Suggested fix
Add the country predicate to
WHERE, and verify the update affected exactly one row before returning success:Severity
High.