langgenius / langgenius/dify

fix(security): harden AgentDriveArchiveMemberApi signed-URL verification

Open
#39,522 0 comments 1 reaction 0 assignees View on GitHub
Dominant language
TypeScript
Stars
156k
Forks
24.6k
Avg merge
22h 9m
Merged PRs (30d)
610

Description

## AgentDriveArchiveMemberApi signed-URL verification is non-constant-time, accepts future timestamps, and has no replay protection

`api/services/agent_drive_service.py` `verify_archive_member_signature` is the sole authorization on the unauthenticated `GET /files/agent-drive/archive-member` endpoint. Three weaknesses in the verification together let an attacker who intercepts a signed URL (logs, browser history, referer leaks, accidental sharing) read the underlying archive bytes indefinitely and also brute-force the signature itself.

### Issues

1. **Non-constant-time signature comparison** (`agent_drive_service.py:1206`). The verification uses `sign != cls._sign_archive_member_payload(payload)`, which short-circuits on the first mismatching byte and leaks signature bytes via timing. The signature can be brute-forced one byte at a time from a network-adjacent position.

2. **No lower-bound timestamp check** (`agent_drive_service.py:1209`). Only the upper bound is enforced (`current_time - int(timestamp) <= FILES_ACCESS_TIMEOUT`). A captured URL with a forged far-future timestamp stays valid indefinitely. There is no check that the timestamp is not in the future, even with a small clock-skew allowance.

3. **No replay protection.** The `nonce` field is part of the signed payload but is never recorded server-side, so a captured URL is fully replayable for the entire access window.

### Attack scenarios

- Intercept any signed archive-member URL — from server access logs, browser history, accidental sharing, or referer leakage — and reuse it indefinitely. Default `FILES_ACCESS_TIMEOUT` is 300 seconds; the lack of nonce tracking means a single interception is enough.
- Brute-force the signature one byte at a time by measuring response time. The endpoint is unauthenticated, so the attacker can probe from any IP.

### Fix

1. Replace `sign != ...` with `hmac.compare_digest(sign, ...)`.
2. Reject timestamps that are more than a small clock-skew window in the future, in addition to the existing upper-bound check.
3. Record the nonce in Redis with the same TTL as the access window using `SET ... NX` for atomic first-use semantics; repeat attempts find the key already present and are rejected.

Contributor guide

Open the contributing guide

Research direction

Start in api/services/agent_drive_service.py at verify_archive_member_signature and the unauthenticated GET /files/agent-drive/archive-member entry point. Trace the existing timestamp and payload checks, then review the Redis access pattern needed for atomic nonce recording. Done means signature comparison is constant-time, future timestamps are rejected within a clock-skew window, and nonce reuse is rejected for the access window.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, redis
Domain
api, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.