elastic / elastic/integrations
[bug-hunter] Proofpoint On Demand websocket cursor corrupts `sinceTime` values containing `+`
- Dominant language
- Handlebars
- Stars
- 333
- Forks
- 647
- Avg merge
- 2d 17h
- Merged PRs (30d)
- 225
Description
## Impact
Proofpoint On Demand `message` stream reconnects can request the wrong cursor value when the stored timestamp has a positive timezone offset (for example `+0000`, `+0530`). Because `sinceTime` is concatenated directly into the URL, `+` is interpreted as a space during query parsing. This can cause duplicate ingestion or missed events after reconnect.
## Reproduction Steps
1. Save and run this new minimal repro script:
```python
from urllib.parse import urlparse, parse_qs
base = "(example.test/redacted)
last_timestamp = "2026-03-10T10:00:00.000000+0000"
# Mirrors websocket.yml.hbs logic: state.url+"&sinceTime=" + state.cursor.last_timestamp
actual_url = base + "&sinceTime=" + last_timestamp
parsed = parse_qs(urlparse(actual_url).query)
actual_since = parsed.get("sinceTime", [None])[0]
expected_since = last_timestamp
print("constructed_url:", actual_url)
print("parsed_sinceTime:", repr(actual_since))
print("expected_sinceTime:", repr(expected_since))
if actual_since != expected_since:
print("FAIL: sinceTime changed during query parsing because '+' was not URL-encoded")
raise SystemExit(1)
print("PASS")
```
2. Run:
```bash
python /tmp/gh-aw/agent/repro_proofpoint_since_time.py
```
## Expected vs Actual
**Expected:** `sinceTime` remains `2026-03-10T10:00:00.000000+0000`.
**Actual:** `sinceTime` becomes `2026-03-10T10:00:00.000000 0000` (plus sign decoded as space), and the script exits with status 1.
Actual output:
```text
constructed_url: (example.test/redacted)
parsed_sinceTime: '2026-03-10T10:00:00.000000 0000'
expected_sinceTime: '2026-03-10T10:00:00.000000+0000'
FAIL: sinceTime changed during query parsing because '+' was not URL-encoded
```
## Failing Test
```python
from urllib.parse import urlparse, parse_qs
base = "(example.test/redacted)
last_timestamp = "2026-03-10T10:00:00.000000+0000"
actual_url = base + "&sinceTime=" + last_timestamp
parsed = parse_qs(urlparse(actual_url).query)
actual_since = parsed.get("sinceTime", [None])[0]
assert actual_since == last_timestamp
```
## Evidence
- `packages/proofpoint_on_demand/data_stream/message/agent/stream/websocket.yml.hbs:3-4` concatenates `sinceTime` without URL encoding:
- `state.url+"&sinceTime="+state.cursor.last_timestamp`
- `packages/proofpoint_on_demand/data_stream/message/agent/stream/websocket.yml.hbs:13` stores cursor from event timestamp:
- `"last_timestamp": body.ts`
- `packages/proofpoint_on_demand/data_stream/message/sample_event.json:54` shows timestamp values include timezone offsets in this stream format.
---
[What is this?](https://ela.st/github-ai-tools) | [From workflow: Bug Hunter](https://github.com/elastic/integrations/actions/runs/23242124791)
Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.
> - [x] expires on Mar 25, 2026, 11:28 AM UTC
Contributor guide
Assessment
This issue has not been assessed yet.