Skip to main content

Server security

This section covers the verification of server-level security controls for a Passwork on-premise deployment. For cloud-hosted instances, network and certificate controls are managed by Passwork infrastructure — focus this review on application-level settings.


1. TLS / HTTPS

What to verify

1.1 HTTPS enforced

All HTTP requests must redirect to HTTPS. Verify with:

curl -I http://your.passwork.url/
# Expected: HTTP/1.1 301 Moved Permanently
# Location: https://your.passwork.url/

1.2 Valid certificate in production

Self-signed certificates are acceptable only in isolated development or PoC environments. Production deployments require a certificate signed by a trusted CA (Let's Encrypt, internal CA for air-gapped networks, or a commercial CA).

Check the certificate:

openssl s_client -connect your.passwork.url:443 -servername your.passwork.url 2>/dev/null \
| openssl x509 -noout -issuer -subject -dates

Verify:

  • Issuer is a trusted CA (not self-signed)
  • notAfter is at least 30 days in the future
  • Subject matches the hostname (CN or SAN)

1.3 TLS version

TLS 1.2 minimum. TLS 1.3 preferred. SSLv3, TLS 1.0, and TLS 1.1 must be disabled.

nmap --script ssl-enum-ciphers -p 443 your.passwork.url

Or use an external scanner: SSL Labs, testssl.sh.

Expected grade: A or higher.

1.4 HSTS header present

The Strict-Transport-Security header prevents browsers from accessing the site over HTTP after the first HTTPS connection.

curl -s -I https://your.passwork.url/ | grep -i strict
# Expected: strict-transport-security: max-age=31536000; includeSubDomains
Default configuration

For Docker builds, HSTS is configured in conf/nginx/nginx.conf. For Apache2/IIS, it is set in the virtual host configuration. If the header is missing, see SSL termination.


2. HTTP security headers

Passwork sets the following headers by default in Docker (Nginx extra/security-headers.conf) and Apache2 (.htaccess). Verify all are present.

curl -s -I https://your.passwork.url/ | grep -iE "x-frame|x-content|x-xss|referrer|permissions|strict"
HeaderExpected valueRisk if missing
X-Frame-OptionsDENYClickjacking
X-Content-Type-OptionsnosniffMIME sniffing attacks
X-XSS-Protection1; mode=blockXSS in legacy browsers
Referrer-Policystrict-origin-when-cross-originReferrer leakage
Permissions-Policycamera=(), microphone=(), geolocation=()Unnecessary API access
Strict-Transport-Securitymax-age=31536000; includeSubDomainsDowngrade/MITM attacks

For configuration details, see Headers.

If any header is missing

For Docker: verify that extra/security-headers.conf is included in the Nginx config and that the container has been restarted after changes. For Apache2: verify that .htaccess processing is enabled (AllowOverride All).


3. CORS configuration

CORS controls which external origins can make requests to the Passwork API.

Default configuration risk: The default Docker cors.conf sets Access-Control-Allow-Origin: *, which permits any origin to make cross-origin requests. This is acceptable when Passwork is deployed on a private network with no external access, but must be reviewed if the instance is internet-accessible.

What to verify

Check the current CORS header:

curl -s -I -H "Origin: https://attacker.example.com" https://your.passwork.url/api/ \
| grep -i access-control

Finding: If the response includes Access-Control-Allow-Origin: * and the server is internet-accessible, restrict the origin to the exact Passwork URL.

How to restrict (Docker):

Edit conf/nginx/extra/cors.conf and replace the wildcard with a specific origin pattern. See Headers — CORS configuration for the exact configuration.


4. Network hardening

MongoDB

MongoDB must not be accessible from the internet. Verify:

# From an external host:
nc -zv your.passwork.url 27017
# Expected: Connection refused

Correct configuration: MongoDB binds to 127.0.0.1 (loopback) or a private network interface only. It must never bind to 0.0.0.0 in a production environment.

On-premise deployments should also verify that MongoDB authentication is enabled. See MongoDB Authorization Configuration.

Firewall / exposed ports

Only the following ports should be accessible from untrusted networks:

PortProtocolPurpose
443TCPHTTPS (Passwork web interface and API)
80TCPHTTP (redirect to HTTPS only)

All other ports (27017 for MongoDB, database replication ports, internal admin interfaces) must be blocked at the network firewall level.

Reverse proxy and trusted proxies

If Passwork is deployed behind a reverse proxy (Nginx, Apache, HAProxy, cloud load balancer), configure trusted proxies in config.env:

CLIENT_IP_SOURCES=REMOTE_ADDR

Or restrict to known proxy IPs to prevent IP spoofing via the X-Forwarded-For header. See Trusted Proxies.


5. Health check endpoint

Passwork exposes a health check endpoint at /api/latest/health-check. This endpoint can reveal system status information.

What to verify

Check whether the endpoint requires authentication:

curl -s https://your.passwork.url/api/latest/health-check

If the endpoint returns data without a token, configure HEALTH_CHECK_TOKEN in config.env:

HEALTH_CHECK_TOKEN=<random-256-bit-string>

After configuration, the endpoint requires the token in the request header. See Health Check.


6. Emergency reset mode

The IS_EMERGENCY_RESET_ENABLED=1 flag in config.env allows password and 2FA reset for the Owner account via the server console without authentication. This is a powerful recovery mechanism that must not remain enabled after use.

What to verify

On the server, check the config file:

# Linux
grep "IS_EMERGENCY_RESET_ENABLED" /var/www/init/config.env

# Docker
grep "IS_EMERGENCY_RESET_ENABLED" /<passwork>/conf/keys/config.env

Acceptable values:

  • Setting not present → correct
  • IS_EMERGENCY_RESET_ENABLED=0 → correct
  • IS_EMERGENCY_RESET_ENABLED=1finding: must be set to 0 or removed

If this flag was used recently, verify in the audit log that only the expected owner account was accessed.

For emergency reset procedure, see Emergency Mode.


7. Background tasks and LDAP sync freshness

Background tasks drive LDAP synchronization, password expiration checks, and other automated maintenance. If cron is not running, LDAP group membership may be stale — users who left an AD group may retain vault access in Passwork.

What to verify

In the Passwork admin panel, go to Settings → Background tasks and verify:

  • All tasks show a recent Start time timestamp (within the expected schedule window)
  • No tasks show error status
Background tasks status page

For cron configuration details, see Cron Setup for Linux or Windows Task Scheduler Setup.


Summary checklist

#ControlStatus
1.1HTTP → HTTPS redirect active
1.2Valid CA-signed SSL certificate
1.3TLS 1.2+ only; legacy TLS disabled
1.4HSTS header present with includeSubDomains
2All 6 security headers present
3CORS origin restricted (if internet-accessible)
4.1MongoDB port 27017 not externally accessible
4.2MongoDB authentication enabled
4.3Only ports 80/443 exposed to untrusted networks
4.4Trusted proxies configured (if behind reverse proxy)
5Health check endpoint protected with token
6IS_EMERGENCY_RESET_ENABLED is 0 or absent
7Background tasks running on schedule