Skip to content

Complete the privacy notice, and stop user text reaching logs - #36

Merged
Robbie1977 merged 2 commits into
mainfrom
fix/privacy-notice-article-13
Aug 19, 2026
Merged

Complete the privacy notice, and stop user text reaching logs#36
Robbie1977 merged 2 commits into
mainfrom
fix/privacy-notice-article-13

Conversation

@Robbie1977

Copy link
Copy Markdown
Contributor

Two things the DPIA needs before it can be submitted honestly. Both were found
by re-reading the code rather than the documentation.

The privacy notice

It was missing four Article 13 essentials: it never identified the controller,
gave no lawful basis, listed only access and erasure among the rights, and
offered no route to the ICO. The transparency answer in the assessment rests
entirely on that page, and it is the first thing an assessor opens.

It now names the University of Edinburgh as controller with its ICO registration;
states Article 6(1)(e) public task, grounded in the Universities (Scotland) Acts
1858 to 1966 and the Further and Higher Education (Scotland) Act 2005, with
consent for an optionally attached transcript; gives the full rights list and how
to use the response identifier; and gives the ICO complaint route.

Article 6(3) attaches to the task rather than to the individual processing
activity, so no statutory power naming this service is needed. Legitimate
interests was considered and is not available: Article 6(1) provides that points
(ea) and (f) do not apply to processing carried out by a public authority in the
performance of its tasks, and the IP address held for abuse prevention exists
solely to keep a public-task service available.

The notice also now says the service reads from PubMed and bioRxiv and what is
sent to them — not an Article 13 disclosure, since no personal data goes, but the
page describes how answers are built and should not leave it out.

Three places user-derived text was going somewhere it should not

Blocked hostnames were kept by name for 26 months. They are extracted from a
user's question by regex, so a fragment of what someone wrote sat in the
long-retention tier. Now a count. The names remain in the 30-day security and
blocked-search logs, which is where an abuse investigation would look.

A failing tool logged its arguments by shape and the upstream error verbatim
beside them.
get_reviewed_page takes a URL whose path is unconstrained — only
the host is allow-listed — and the fetcher throws it back in the message, so the
redaction was defeated by the value next to it. Errors now go through safeText
at all five sites.

The argument value test was "contains no whitespace", which a URL and a
70-character lab identifier both pass. It is now identifier-shaped: 40
characters, no path separators. Real VFB vocabulary still prints, so the
diagnostic keeps its value.

The leak guard caught none of these — it planted its canary only in the question
and the term name, and its tool-failure case threw an error containing no user
text. Two new cases close both paths.

Also

NCBI_EMAIL is passed through docker-compose.yml; it was set on the server but
never reached the container, because Compose forwards only what is listed. And
the chat's opening guidance now names personal data, where it said only
"confidential or sensitive".

Note on the branch

This replaces an earlier branch cut before #34 and #35 merged. That branch had
picked up two CI-generated task-battery result files, and its app/page.js was a
pre-#34 snapshot — merging it would have reverted #34's two contrast fixes. This
is one clean commit on top of 783c1fb, with only the single welcome-message
line applied to app/page.js.

Verification

  • node --test tests/unit/*.test.mjs — 1279 pass, 0 fail
  • node scripts/a11y-audit.mjs — 0 violations across all five targets, including
    the answered state
  • next build clean

Robbie1977 and others added 2 commits August 19, 2026 19:07
Two things the DPIA needs before it can be submitted honestly.

The privacy notice was missing four Article 13 essentials: it never
identified the controller, gave no lawful basis, listed only access and
erasure among the rights, and offered no route to the ICO. The
transparency answer in the assessment rests entirely on that page, and it
is the first thing an assessor opens.

It now names the University of Edinburgh as controller with its ICO
registration; states Article 6(1)(e) public task, grounded in the
Universities (Scotland) Acts 1858 to 1966 and the Further and Higher
Education (Scotland) Act 2005, with consent for an optionally attached
transcript; gives the full rights list and how to use the response
identifier; and gives the ICO complaint route. Article 6(3) attaches to
the task rather than to the individual processing activity, so no
statutory power naming this service is needed. Legitimate interests was
considered and is not available: Article 6(1) provides that points (ea)
and (f) do not apply to processing carried out by a public authority in
the performance of its tasks, and the IP address held for abuse
prevention exists solely to keep a public-task service available.

The notice also now says the service reads from PubMed and bioRxiv and
what is sent to them. Not an Article 13 disclosure, since no personal
data goes, but the page describes how answers are built and should not
leave it out.

Then three places user-derived text was reaching somewhere it should not,
all found by re-reading the code rather than the documentation.

Blocked hostnames were kept by NAME for 26 months. They are extracted
from a user's question by regex, so a fragment of what someone wrote sat
in the long-retention tier. Now a count. The names remain in the 30-day
security and blocked-search logs, which is where an abuse investigation
would look.

A failing tool logged its arguments by shape and the upstream error
verbatim beside them. get_reviewed_page takes a URL whose path is
unconstrained - only the host is allow-listed - and the fetcher throws it
back in the message, so the redaction was defeated by the value next to
it. Errors now go through safeText at all five sites.

The argument value test was "contains no whitespace", which a URL and a
70-character lab identifier both pass. It is now identifier-shaped: 40
characters, no path separators. Real VFB vocabulary still prints, so the
diagnostic keeps its value.

The leak guard caught none of these: it planted its canary only in the
question and the term name, and its tool-failure case threw an error
containing no user text. Two new cases close both paths.

Also: pass NCBI_EMAIL through docker-compose, which was set on the server
but never reached the container because Compose forwards only what is
listed; and name personal data in the chat's opening guidance, which said
only confidential or sensitive.
@Robbie1977
Robbie1977 merged commit 674bc8a into main Aug 19, 2026
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.

1 participant