Ghostwriter v7.0.0
Summary
This release marks a significant turn in automation. It hardens authentication by replacing user-managed JWT API tokens with opaque gwat_ credentials, adding scoped gwst_ service tokens for non-human integrations, tightening JWT/session validation, and moving service-token GraphQL access to a scoped service role. Existing user-managed JWT API tokens should be re-rolled by rotating them to receive a new opaque API token; changing an API token’s expiry now also generates a replacement token and immediately invalidates the old credential, so dependent automation must be updated with the newly shown token. Admin-created user-bound API tokens should be replaced with either user-created API tokens or scoped service tokens, depending on whether the credential should act as a human user or a non-human service.
Read more here: https://www.ghostwriter.wiki/features/access-authentication-and-session-controls/user-profile-and-tokens
CHANGELOG
[7.0.0] - 3 June 2026
Breaking Changes
- User-managed API tokens are now opaque
gwat_credentials instead of JWTs- Existing user-managed JWT API tokens must be rotated to receive an opaque API token
- API token expiry edits rotate the token prefix, secret hash, and UUID identifier, which immediately invalidates the previous credential
- Django admin can no longer create user-bound API tokens
- Use service principals and service tokens for non-human integrations
- Admin-created user-bound API tokens should be replaced with user-created API tokens or scoped service tokens, depending on whether the credential should act as a user or as a non-human service
- Login and collaborative editor JWTs now use explicit JWT typing and are accepted only by their intended authentication paths
- Collaborative editor JWTs authenticate to Hasura only as a restricted
collabrole for the editor's required read-only queries - Login JWTs require a tracked, unrevoked user session bound by the
jticlaim
- Collaborative editor JWTs authenticate to Hasura only as a restricted
- Service-token GraphQL access now uses the new
servicerole and scoped service-token permissions instead of inheriting a creating user's permissions
Added
- Scoped Service Tokens: Added service principals and service tokens for non-human automation credentials (Closes #881)
- Service principals represent durable integrations or automation services
- Service tokens are opaque
gwst_credentials with hashed secrets, expiration, revocation, and last-used tracking - Service token permissions are assigned to the token instead of inheriting the creating user's permissions
- Added operation log read/write tokens scoped to one operation log and its entries
- Added project read-only tokens scoped to selected projects or all projects the creator can access now and later
- Service Token GraphQL Access: Added a Hasura
servicerole for scoped service-token access- The shared
servicerole exposes a combined service-token schema; each token's grants still determine which protected rows and Actions it can use - Project read access is backed by database views that validate the service token, service principal, creator status, and current project access
- Service tokens can read project-related data, project-linked operation logs, evidence, reports, findings, observations, and public libraries
- Service tokens can call selected read-oriented GraphQL Actions when their token grants allow the target resource, including report generation, evidence and recording downloads, tag lookups, and extra field specs
- The shared
- Added service-token management to the Django admin
- Added documentation for API tokens, service tokens, and service-principal concepts
- Added user-session tracking for login JWTs so administrators can revoke active GraphQL sessions
- Added a management command to clean up expired Django sessions and tracked GraphQL login sessions
Changed
- Reworked the user profile page to organize API tokens and service tokens into clearer cards
- API tokens are described as user-bound automation credentials
- Service tokens are described as scoped non-human credentials
- Expired tokens can be hidden, and that preference is remembered in local storage
- Token expiry dates now use warning styling when expiring within seven days and expired styling after expiration
- API tokens now show last-used timestamps alongside service tokens
- API tokens now have lazy-loaded details modals showing the token user's current project access
- Added profile controls for editing API token and service token expiry dates
- API token expiry edits now generate a replacement opaque token so the previous credential stops working immediately
- Added service-token detail modals that show service principal, project read access, direct operation-log access, stale project grants, and token access summaries
- Improved dark-mode styling for disabled fields
- Made the sidebar toggle tab sticky while scrolling
- Added the
DJANGO_MFA_PASSKEY_LOGIN_ENABLEDenvironment variable for controlling passkey login support - API tokens are now opaque
gwat_credentials with hashed secrets instead of user-managed JWTs- Editing an API token expiry rotates the token prefix, secret hash, and UUID identifier
- Login and collaborative editor JWTs now use explicit JWT typing
- Login JWTs bind their
jticlaim to a tracked user-session identifier - Collaborative editor JWTs use a dedicated token type and restricted Hasura role
- Login JWTs bind their
Fixed
- Fixed observation library create/edit/delete permissions not being checked for the
userrole in the GraphQL API - Fixed token tables showing as empty when Hide Expired hides every API token or service token
- Fixed hyperlinks not working properly in open Office alternatives like LibreOffice (Fixes #890; Thanks to @wexew-ware)
Security
- Updated Django from 4.2.16 to 4.2.30 to address CVE-2026-3902 in
ASGIRequest(Fixes #896) - Added service-token authorization helpers for Django-backed Hasura Actions so service tokens are denied by default unless an action explicitly opts in
- Login JWT validation now checks the tracked user session after verifying the JWT signature and expiration so sessions can be revoked on demand
- Collaborative editor JWTs are restricted to a dedicated Hasura role and accepted by the collaborative editor permission-check endpoint
- API token validation now verifies the opaque token secret against a stored hash and rejects revoked, expired, or inactive-user tokens
- API token expiry edits now invalidate the previous credential and show the replacement token once
- Service-token validation now uses explicit secret-checking terminology internally and keeps full lifecycle validation on the manager path
- Added Hasura metadata validation tests to catch service-role permission drift, legacy service-token headers, and unexpected service mutations
- Added validation for service-token permission resource, action, and constraint combinations