- Location
- agentsync/webui/__init__.py:425
- Finding
- Unauthenticated loopback Web UI exposes state-changing backup, restore, deletion, and path-binding APIs<![CDATA[
## Vulnerability Details
**File Location**: `agentsync/webui/__init__.py:425-505,511-522`
**Vulnerability Type**: Missing authentication and cross-origin request protection
**Risk Level**: High
### Vulnerable Code
The request handler performs state-changing operations without authentication, authorization, CSRF tokens, origin checks, host validation, or content-type validation:
```python
def do_POST(self) -> None:
u = urlparse(self.path)
if u.path == "/api/bind-path":
try:
n = int(self.headers.get("Content-Length") or 0)
body = json.loads(self.rfile.read(n).decode("utf-8")) if n else {}
out = paths.bind_override(
str(body.get("source", "")),
str(body.get("path", "")),
)
return self._json(out, 200 if out.get("ok") else 400)
except Exception as e:
return self._json(
{"ok": False, "detail": f"{type(e).__name__}: {e}"},
400,
)
if u.path == "/api/backup":
try:
n = int(self.headers.get("Content-Length") or 0)
body = json.loads(self.rfile.read(n).decode("utf-8")) if n else {}
from .. import backup as backup_mod
src = str(body.get("source", ""))
if src not in SOURCES:
return self._json(
{"ok": False, "detail": f"unknown source: {src}"},
400,
)
raw_ids = body.get("ids") or ""
ids = {i for i in str(raw_ids).split(",") if i} or None
if src in backup_mod.RAW_SOURCES:
rows = backup_mod.do_raw_backup([src], paths.detect())
else:
rows = backup_mod.do_backup(
[src],
paths.detect(),
with_imports=bool(body.get("with_imports")),
ids=ids,
)
return self._json({"ok": True,
...[truncated 4944 chars]
- Remediation
- <![CDATA[
## Remediation Suggestions
1. Generate a cryptographically random per-launch authentication token.
2. Require the token in an authorization header for every API request, especially all POST requests.
3. Generate and validate a separate anti-CSRF token for browser actions.
4. Validate the `Origin` header against the exact dashboard origin.
5. Validate the `Host` header against the expected loopback address and active port to mitigate DNS rebinding.
6. Require `Content-Type: application/json` and reject other content types.
7. Implement restrictive CORS behavior and do not reflect arbitrary origins.
8. Require explicit interactive confirmation immediately before restore and deletion operations.
9. Consider moving restore and deletion back to the CLI, where existing dry-run and human-confirmation controls can be applied.
10. Refuse restoration while the target application is running.
11. Separate read-only and write-capable server modes, with read-only as the default.
12. Correct the dashboard message and documentation so that they do not describe the service as read-only while write endpoints are enabled.
13. Add security headers such as a restrictive Content Security Policy and `X-Content-Type-Options: nosniff`.
14. Rate-limit sensitive endpoints and log state-changing operations with source, target, timestamp, and result.
]]>