---
path: onboarding/security-review/server-security.mdx
title: Server security
sidebar_position: 2
slug: server-security
pagination_next: null
pagination_prev: null
description: >-
  Security review checklist for Passwork server infrastructure: TLS configuration,
  HTTP security headers, CORS, network hardening, emergency mode controls, and
  health check endpoint protection.
keywords:
  - Passwork
  - server security
  - TLS
  - HTTPS
  - security headers
  - HSTS
  - CORS
  - network hardening
  - MongoDB
  - firewall
  - health check
  - emergency mode
---

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:

```bash
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:

```bash
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.

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

Or use an external scanner: [SSL Labs](https://www.ssllabs.com/ssltest/), [testssl.sh](https://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.

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

:::info 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](https://passwork.pro/tech-guides/administration/advanced-settings/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.

```bash
curl -s -I https://your.passwork.url/ | grep -iE "x-frame|x-content|x-xss|referrer|permissions|strict"
```

<Table
  headers={[
    { content: 'Header' },
    { content: 'Expected value' },
    { content: 'Risk if missing' },
  ]}
  rows={[
    {
      cells: [
        { content: <code>X-Frame-Options</code> },
        { content: <code>DENY</code> },
        { content: 'Clickjacking' },
      ],
    },
    {
      cells: [
        { content: <code>X-Content-Type-Options</code> },
        { content: <code>nosniff</code> },
        { content: 'MIME sniffing attacks' },
      ],
    },
    {
      cells: [
        { content: <code>X-XSS-Protection</code> },
        { content: <code>1; mode=block</code> },
        { content: 'XSS in legacy browsers' },
      ],
    },
    {
      cells: [
        { content: <code>Referrer-Policy</code> },
        { content: <code>strict-origin-when-cross-origin</code> },
        { content: 'Referrer leakage' },
      ],
    },
    {
      cells: [
        { content: <code>Permissions-Policy</code> },
        { content: <code>camera=(), microphone=(), geolocation=()</code> },
        { content: 'Unnecessary API access' },
      ],
    },
    {
      cells: [
        { content: <code>Strict-Transport-Security</code> },
        { content: <code>max-age=31536000; includeSubDomains</code> },
        { content: 'Downgrade/MITM attacks' },
      ],
    },
  ]}
/>

For configuration details, see [Headers](https://passwork.pro/tech-guides/administration/advanced-settings/headers/).

:::warning 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:

```bash
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](https://passwork.pro/tech-guides/administration/advanced-settings/headers/#cross-origin-resource-sharing) for the exact configuration.

---

## 4. Network hardening

### MongoDB

MongoDB must not be accessible from the internet. Verify:

```bash
# 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](https://passwork.pro/tech-guides/databases/mongodb/authorization-configuration-examples/intro/).

### Firewall / exposed ports

Only the following ports should be accessible from untrusted networks:

| Port | Protocol | Purpose |
|------|----------|---------|
| 443 | TCP | HTTPS (Passwork web interface and API) |
| 80 | TCP | HTTP (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](https://passwork.pro/tech-guides/administration/advanced-settings/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:

```bash
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](https://passwork.pro/tech-guides/api-and-integrations/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:

```bash
# 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=1` → **finding: 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](https://passwork.pro/tech-guides/administration/advanced-settings/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

<ImageComponent
  src="/img/assets/background-tasks-1.png"
  alt="Background tasks status page"
  format="regular"
/>

For cron configuration details, see [Cron Setup for Linux](https://passwork.pro/tech-guides/administration/background-tasks/cron-setup-for-linux/intro/) or [Windows Task Scheduler Setup](https://passwork.pro/tech-guides/administration/background-tasks/windows-task-scheduler-setup/).

---

## Summary checklist

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