Skip to content

Authorise on the acting role, and stop an upload from being a page - #2000

Merged
vikrantwiz02 merged 4 commits into
FusionIIIT:prod/acad-reactfrom
vikrantwiz02:security-acting-role-and-uploads
Sep 30, 2026
Merged

vikrantwiz02 merged 4 commits into
FusionIIIT:prod/acad-reactfrom
vikrantwiz02:security-acting-role-and-uploads

Conversation

@vikrantwiz02

Copy link
Copy Markdown
Member

Four security fixes in the portal, found while reviewing what the single login and single sidebar expose.

Authority follows the acting role

role_required checked the set of designations somebody holds. A student who also holds an office kept that office's authority while acting as a student, so anything reaching their session — an XSS above all — reached the office's endpoints with it. It now checks the role being acted in, defaulting to the office when the switcher has never been used, so nobody is locked out.

Keyed on HoldsDesignation.working instead of user, which is what the model's own docstring asks for and what the IAM already projects. Reading the other one authorises somebody on leave and refuses their stand-in.

update_last_selected_role accepted any string and stored it — harmless while it only drove the sidebar, a free promotion once authorisation reads it. A post nobody holds is now refused.

An upload is a download, never a page

Uploads are served from the same origin as the portal and every module framed inside it. A file served inline runs as the application, so an uploaded .html or .svg would execute in this origin and could read the API token the client keeps in localStorage. They now go out as attachment with nosniff and a sandbox policy, whatever the file claims to be.

Credentials that stop working

A DRF token never expires and this one lives in localStorage, so a copy taken once works for good. ExpiringTokenAuthentication bounds it; the settings switch is deployment's to make. The IAM session cookie was secure only when an environment variable said so, and now follows DEBUG.

OTP off the request path

The reply waited on the full SMTP round-trip, although the OTP row is saved before the send and the caller is told the same thing either way. It now goes to a thread.

Tests

12 new, covering the parts that decide access: the acting role, a stand-in against the absent holder, a role no longer held, an upload served as a download, a token past its life, and a slow mail host not holding the request. 50 pass in this app.

Not in this PR

DEBUG = True, CORS_ORIGIN_ALLOW_ALL, the committed Google and database credentials, and the transport-security settings are all in Fusion/settings/, which the deployment overwrites. They are being applied on the server, and the two secrets need rotating.

role_required checked the set of designations somebody holds, so a student
who also holds an office kept that office's authority while acting as a
student — and anything reaching their session reached the office's endpoints
with it. It now checks the acting role, defaulting to the office when the
switcher has never been used, so nobody is locked out.

Keyed on HoldsDesignation.working rather than user, which is what the model's
own docstring asks for and what the IAM already projects: reading the other
one authorises somebody on leave and refuses their stand-in.

update_last_selected_role accepted any string and stored it. That was
harmless while it only drove the sidebar and a free promotion once
authorisation reads it, so a post nobody holds is now refused.
Uploads are served from the same origin as the portal and every module framed
inside it, so a file served inline runs as the application: an uploaded .html
or .svg would execute in this origin and could read the API token the client
keeps in localStorage.

Forcing attachment, nosniff and a sandbox policy takes that away whatever the
file claims to be, and holds whether or not the media route is reachable.
A DRF token never expires, and this one lives in localStorage where any script
on the origin can read it, so a copy taken once works for good. The class is
here; the settings switch is deployment's to make.

The IAM session cookie was secure only when an environment variable said so.
It now follows DEBUG, still overridable, so one plain-HTTP request no longer
puts the session on the wire.
…tests

The reply waited on the full SMTP round-trip although the OTP row is already
saved before the send and the caller is told the same thing either way — so
the wait bought nothing. It now goes to a thread.

Tests for the parts that decide access: the acting role, a stand-in against
the absent holder, a role no longer held, an upload served as a download, and
a token past its life.
@vikrantwiz02
vikrantwiz02 merged commit b33dfc1 into FusionIIIT:prod/acad-react Sep 30, 2026
1 check 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.

1 participant