asf-tooling opened a new issue, #1029:
URL: https://github.com/apache/tooling-trusted-releases/issues/1029

   **ASVS Level(s):** [L1, L2]
   
   **Description:**
   
   ### Summary
   JWTs issued through the web UI (`/tokens/jwt`) are not bound to any PAT and 
remain valid for their full 30-minute TTL regardless of logout or 
authentication factor changes. Only JWTs with the `atr_th` (PAT hash) claim are 
validated against the PAT database. The `jwtoken.issue()` function generates a 
`jti` (JWT ID) claim for all JWTs, but this claim is never checked against any 
denylist or revocation registry. When `jwtoken.verify()` validates a JWT, it 
only checks the PAT hash (`atr_th`) if present - web-issued JWTs skip this 
check entirely. This creates inconsistency: PAT-issued JWTs are immediately 
revoked when PAT is deleted, but web-issued JWTs continue working for up to 30 
minutes, violating ASVS 7.4.1 and 7.4.3 principles of immediate invalidation.
   
   ### Details
   Affected locations:
   - `atr/post/tokens.py` lines 33-41: jwt_post() issues JWT without PAT binding
   - `atr/jwtoken.py` lines 42-58: issue() generates jti but no denylist check
   - `atr/jwtoken.py` lines 92-126: verify() only checks PAT hash if present
   
   Web-issued JWTs have no revocation mechanism and survive for full 30-minute 
TTL.
   
   ### Recommended Remediation
   **Option A (recommended):** Extend the per-user revocation timestamp 
approach from SESSION-001 to cover JWTs. Update `jwtoken.verify()` to check the 
user's `sessions_invalid_before` timestamp against the JWT's `iat` (issued at) 
claim:
   
   ```python
   def verify(token: str) -> dict:
       claims = jwt.decode(token, signing_key, algorithms=['HS256'])
       
       # Check user's revocation timestamp
       user = get_user(claims['sub'])
       if user.sessions_invalid_before and claims['iat'] < 
user.sessions_invalid_before:
           raise JWTTokenInvalid("JWT issued before revocation timestamp")
       
       # Existing PAT hash check
       if 'atr_th' in claims:
           # ... existing PAT validation
       
       return claims
   ```
   
   This provides unified revocation for both web sessions and JWTs using a 
single database column.
   
   **Option B:** Require all JWTs to be issued through PATs - modify 
`jwt_post()` to check if user has at least one PAT, raise BadRequest if none 
exist, bind JWT to first PAT using pat_hash parameter.
   
   **Option C:** Add JTI denylist using Redis for granular JWT revocation.
   
   **Option D (minimal):** Reduce web-issued JWT TTL from 30 minutes to 5 
minutes to limit exposure window.
   
   ### Acceptance Criteria
   - [ ] Web-issued JWTs can be revoked
   - [ ] Revocation is immediate or near-immediate
   - [ ] Consistency with PAT-issued JWT revocation
   - [ ] Test cases verify JWT revocation
   - [ ] Unit test verifying the fix
   
   ### References
   - Source reports: L1:7.4.1.md, L2:7.4.3.md
   - Related findings: FINDING-005, FINDING-036
   - ASVS sections: 7.4.1, 7.4.3
   
   ### Priority
   Medium
   
   ---


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to