Identifiers: a pasted address with an unbalanced '[' in the host crashes the page with a 500 #460

Closed
opened 2026-10-01 10:46:52 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading core/identifiers.py and posting a malformed ORCID address to Your details.

Checked again on 2026-10-01 against main at 0a5cad587: still present. The code is now at core/identifiers.py:124 (hosted_by) and core/identifiers.py:132 (value_from_url), reached from Scheme.normalise at core/identifiers.py:108. Of the callers, CompanyIdentifier.clean is now at jobs/models.py:544, Company.by_identifier at jobs/models.py:470, the spreadsheet import's call at core/csv_import.py:952, and _orcid_from moved to plugins/europass/common.py:92 (#248), from where both Europass readers use it; the other callers have not moved, and the same post to Your details still returns 500.

Scheme.normalise lifts an identifier out of a pasted address through hosted_by and value_from_url, and both call urllib.parse.urlsplit, which raises ValueError("Invalid IPv6 URL") when the host part has a [ without its ]. Every caller catches only ValidationError, so the error escapes as a server error instead of the ordinary "That does not look like a … identifier" message.

  • Where: core/identifiers.py:119 (hosted_by: host = (urlsplit(url).hostname or "").lower()) and core/identifiers.py:127 (value_from_url: parts = urlsplit(url)), reached from Scheme.normalise at core/identifiers.py:103. Callers that expect only ValidationError: accounts/models.py:214 (PersonIdentifier.clean, run by the profile form), jobs/models.py:541 and jobs/services.py:29 (company identifiers), jobs/models.py:467 (Company.by_identifier, used by applications/services.py:321, core/csv_import.py:957 and core/importer.py:569), and plugins/europass/reader.py:201 (_orcid_from).
  • What happens: an ORCID row on Your details holding https://[orcid.org/0000-0002-1825-0097 returns 500 (reproduced with the test client). The same holds for the company schemes with URL paths (Wikidata, LinkedIn, LEI, Crunchbase, OpenCorporates), for company_wikidata sent to the listing and application API routes, for a Wikidata column in a spreadsheet import, for a backup archive's company identifiers, and for a Europass file whose websites include such an address: _orcid_from catches ValidationError only, so the whole import page fails.
  • Why it matters: a mistyped paste, or a stray character in somebody's own CV file or spreadsheet, turns into a crash with no hint of which field was at fault, and the import is lost rather than the one value being dropped.
  • Fix: in hosted_by and value_from_url, catch ValueError around urlsplit and answer False and None, so the raw value falls through to the pattern check and is refused with the format message (and _orcid_from simply skips it).

Done when

  • tests/test_person_identifiers.py posts an ORCID row with an unbalanced [ to accounts:profile and gets the page back with the format error, and tests/test_identifiers.py asserts that clean raises ValidationError for https://[wikidata.org/x under the Wikidata scheme.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading `core/identifiers.py` and posting a malformed ORCID address to *Your details*. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. The code is now at `core/identifiers.py:124` (`hosted_by`) and `core/identifiers.py:132` (`value_from_url`), reached from `Scheme.normalise` at `core/identifiers.py:108`. Of the callers, `CompanyIdentifier.clean` is now at `jobs/models.py:544`, `Company.by_identifier` at `jobs/models.py:470`, the spreadsheet import's call at `core/csv_import.py:952`, and `_orcid_from` moved to `plugins/europass/common.py:92` (#248), from where both Europass readers use it; the other callers have not moved, and the same post to *Your details* still returns 500. `Scheme.normalise` lifts an identifier out of a pasted address through `hosted_by` and `value_from_url`, and both call `urllib.parse.urlsplit`, which raises `ValueError("Invalid IPv6 URL")` when the host part has a `[` without its `]`. Every caller catches only `ValidationError`, so the error escapes as a server error instead of the ordinary "That does not look like a … identifier" message. - **Where:** `core/identifiers.py:119` (`hosted_by`: `host = (urlsplit(url).hostname or "").lower()`) and `core/identifiers.py:127` (`value_from_url`: `parts = urlsplit(url)`), reached from `Scheme.normalise` at `core/identifiers.py:103`. Callers that expect only `ValidationError`: `accounts/models.py:214` (`PersonIdentifier.clean`, run by the profile form), `jobs/models.py:541` and `jobs/services.py:29` (company identifiers), `jobs/models.py:467` (`Company.by_identifier`, used by `applications/services.py:321`, `core/csv_import.py:957` and `core/importer.py:569`), and `plugins/europass/reader.py:201` (`_orcid_from`). - **What happens:** an ORCID row on *Your details* holding `https://[orcid.org/0000-0002-1825-0097` returns 500 (reproduced with the test client). The same holds for the company schemes with URL paths (Wikidata, LinkedIn, LEI, Crunchbase, OpenCorporates), for `company_wikidata` sent to the listing and application API routes, for a Wikidata column in a spreadsheet import, for a backup archive's company identifiers, and for a Europass file whose websites include such an address: `_orcid_from` catches `ValidationError` only, so the whole import page fails. - **Why it matters:** a mistyped paste, or a stray character in somebody's own CV file or spreadsheet, turns into a crash with no hint of which field was at fault, and the import is lost rather than the one value being dropped. - **Fix:** in `hosted_by` and `value_from_url`, catch `ValueError` around `urlsplit` and answer `False` and `None`, so the raw value falls through to the pattern check and is refused with the format message (and `_orcid_from` simply skips it). ## Done when - `tests/test_person_identifiers.py` posts an ORCID row with an unbalanced `[` to `accounts:profile` and gets the page back with the format error, and `tests/test_identifiers.py` asserts that `clean` raises `ValidationError` for `https://[wikidata.org/x` under the Wikidata scheme.
tiagoagueda added this to the 0.6.0 milestone 2026-10-01 10:46:52 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#460
No description provided.