{
  "format_version": 3,
  "policy": {
    "external_id": "d4a6acae98dd3e71ae541189f9f9f0ce",
    "name": "CIS MariaDB 10.11 Benchmark v1.0.0 - Level 1",
    "version": "1.0.0",
    "description": "CIS Level 1 hardening profile for MariaDB 10.11 on Linux. Disable client history, datadir permissions, secure server-side flags (allow-suspicious-udfs, symbolic links, secure_file_priv, sql_mode strict), audit logging, legacy auth plugin removed, TLS-only transport, replication cert verification. Requires the agent to authenticate as a user with SELECT on mysql.* and SHOW VARIABLES privileges.",
    "author": "Center for Internet Security"
  },
  "tests": [
    {
      "external_id": "8b9dc3aec713231f5e3cc24ee773b01b",
      "name": "1.3 — Disable MariaDB Command History",
      "description": "Interactive client history (~/.mysql_history, ~/.mariadb_history) can preserve sensitive SQL — credentials embedded in SQL, schema details.",
      "rational": "DBAs running ad-hoc SQL with literal credentials would otherwise leave them on disk indefinitely.",
      "remediation": "Symlink ~/.mariadb_history (and ~/.mysql_history) to /dev/null for every account that runs the client.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "for u in $(getent passwd | awk -F: '$3>=1000 {print $1}'); do hd=$(getent passwd $u | cut -d: -f6); for f in \"$hd/.mariadb_history\" \"$hd/.mysql_history\"; do [ -f \"$f\" ] && [ ! -L \"$f\" ] && echo PRESENT; done; done | head -1",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": "PRESENT"
        }
      ],
      "applicability": []
    },
    {
      "external_id": "6d2deb73792d989d8887d22a3f248d6a",
      "name": "3.1 — Ensure 'datadir' Has Appropriate Permissions",
      "description": "The MariaDB data directory must not be world- or group-readable.",
      "rational": "Other local accounts could otherwise read the raw InnoDB files and recover data without authenticating.",
      "remediation": "Run: `chmod 700 /var/lib/mysql && chown mysql:mysql /var/lib/mysql`.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "stat -c '%a' /var/lib/mysql 2>/dev/null",
          "selement": "OUTPUT",
          "condition": "EQUALS",
          "sinput": "700"
        }
      ],
      "applicability": []
    },
    {
      "external_id": "a6604b4a5e172652dbf1518934ce88c0",
      "name": "4.3 — Ensure 'allow-suspicious-udfs' is Set to 'OFF'",
      "description": "allow-suspicious-udfs lets the server load UDFs that lack the required xxx_init() / xxx_deinit() symbols.",
      "rational": "It dramatically increases the attack surface around the UDF loader.",
      "remediation": "Ensure allow-suspicious-udfs is not set in /etc/mysql/mariadb.conf.d/50-server.cnf (defaults to OFF).",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "mariadb -BN -e \"SHOW VARIABLES LIKE 'allow_suspicious_udfs';\" 2>/dev/null | awk '{print $2}'",
          "selement": "OUTPUT",
          "condition": "EQUALS",
          "sinput": "OFF"
        }
      ],
      "applicability": []
    },
    {
      "external_id": "378ce9c74d595a892b5efad85e5bffaf",
      "name": "4.6 — Ensure Symbolic Links are Disabled",
      "description": "symbolic_links should be OFF so that table files cannot point outside the data directory.",
      "rational": "Symlinked tables can be used to escape the data directory boundary or to overwrite arbitrary files.",
      "remediation": "Add `skip-symbolic-links` under [mysqld] in /etc/mysql/mariadb.conf.d/50-server.cnf.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "mariadb -BN -e \"SHOW VARIABLES LIKE 'have_symlink';\" 2>/dev/null | awk '{print $2}'",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": "YES"
        }
      ],
      "applicability": []
    },
    {
      "external_id": "48d5540f3991d3c9148d5bc70eab7132",
      "name": "4.7 — Ensure 'secure_file_priv' is Configured Correctly",
      "description": "secure_file_priv restricts the directory used by LOAD DATA INFILE and SELECT … INTO OUTFILE.",
      "rational": "Without a restriction, file-based SQL primitives can be used to read or write arbitrary files the server can reach.",
      "remediation": "Set `secure_file_priv=/var/lib/mysql-files/` (or an empty value to disable file operations).",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "mariadb -BN -e \"SHOW VARIABLES LIKE 'secure_file_priv';\" 2>/dev/null | awk '{print $2}'",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": ""
        }
      ],
      "applicability": []
    },
    {
      "external_id": "30f1ee3bf49312817b30e3a59d93b27d",
      "name": "4.8 — Ensure 'sql_mode' Contains STRICT_ALL_TABLES",
      "description": "STRICT_ALL_TABLES makes the server reject invalid data rather than silently truncating it.",
      "rational": "Silent truncation has caused real data-loss and integrity bugs that would have been caught by strict mode.",
      "remediation": "Add `sql_mode=STRICT_ALL_TABLES,...` under [mysqld] in /etc/mysql/mariadb.conf.d/50-server.cnf.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "mariadb -BN -e \"SHOW VARIABLES LIKE 'sql_mode';\" 2>/dev/null | awk '{$1=\"\"; print}' | tr -d ' '",
          "selement": "OUTPUT",
          "condition": "CONTAINS",
          "sinput": "STRICT_ALL_TABLES"
        }
      ],
      "applicability": []
    },
    {
      "external_id": "2c503b9aec2f13605c1c85dc8ae62f54",
      "name": "6.4 — Ensure Audit Logging Is Enabled",
      "description": "The server_audit plugin records connection, query, and table events to a log file.",
      "rational": "Audit trails are required for forensic investigation and most compliance regimes.",
      "remediation": "Install plugin via `INSTALL PLUGIN server_audit SONAME 'server_audit.so';` and set `server_audit_logging=ON`.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "mariadb -BN -e \"SHOW VARIABLES LIKE 'server_audit_logging';\" 2>/dev/null | awk '{print $2}'",
          "selement": "OUTPUT",
          "condition": "EQUALS",
          "sinput": "ON"
        }
      ],
      "applicability": []
    },
    {
      "external_id": "f27a285779882508f3728ad5034f1a82",
      "name": "7.1 — Disable use of the mysql_old_password plugin",
      "description": "The legacy mysql_old_password authentication uses the pre-4.1 password hash, which is trivially crackable.",
      "rational": "Old-style hashes can be brute-forced in seconds on commodity hardware.",
      "remediation": "Ensure no users authenticate with mysql_old_password; convert to mysql_native_password or ed25519.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "mariadb -BN -e \"SELECT COUNT(*) FROM mysql.user WHERE plugin='mysql_old_password';\" 2>/dev/null",
          "selement": "OUTPUT",
          "condition": "EQUALS",
          "sinput": "0"
        }
      ],
      "applicability": []
    },
    {
      "external_id": "c24fddd3ca3f773952cb0df5d86f7b9a",
      "name": "8.1 — Ensure 'require_secure_transport' is Set to 'ON' and 'have_ssl' is Set to 'YES'",
      "description": "require_secure_transport forces clients to connect via TLS; have_ssl confirms the server was built with TLS support.",
      "rational": "Without TLS the credentials and query payloads cross the network in plaintext.",
      "remediation": "Set `require_secure_transport=ON` under [mysqld] and provide ssl-cert / ssl-key paths.",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "mariadb -BN -e \"SHOW VARIABLES WHERE Variable_name IN ('require_secure_transport','have_ssl');\" 2>/dev/null | awk '{print $2}' | sort -u",
          "selement": "OUTPUT",
          "condition": "NOT CONTAINS",
          "sinput": "OFF"
        }
      ],
      "applicability": []
    },
    {
      "external_id": "d62e4da489af8027e37629078e76a78d",
      "name": "9.2 — Ensure 'MASTER_SSL_VERIFY_SERVER_CERT' is enabled",
      "description": "Replication connections must verify the primary's TLS certificate.",
      "rational": "Without verification, a network attacker can intercept and modify replication traffic.",
      "remediation": "On the replica: `STOP SLAVE; CHANGE MASTER TO MASTER_SSL=1, MASTER_SSL_VERIFY_SERVER_CERT=1; START SLAVE;`",
      "severity": "Medium",
      "filter": null,
      "app_filter": null,
      "conditions": [
        {
          "type": "condition",
          "element": "CMD",
          "input": "mariadb -BN -e \"SHOW REPLICA STATUS\\\\G\" 2>/dev/null | awk -F': ' '/Master_SSL_Verify_Server_Cert/ {print $2}'",
          "selement": "OUTPUT",
          "condition": "NOT EQUALS",
          "sinput": "No"
        }
      ],
      "applicability": []
    }
  ]
}