Silencing Apple Passwords and Enabling Third-Party Autofill

Silencing Apple Passwords and Enabling Third-Party Autofill

Introduction
Under normal circumstances, Safari autofill behavior and browser extension states would be managed centrally via a Privacy Preferences Policy Control (PPPC) profile or a Safari-scoped configuration profile deployed through MDM. However, Apple does not expose third-party password manager extension states as managed preference keys, meaning pluginkit Extension enablement for tools such as 1Password and Bitwarden cannot be enforced through a configuration profile payload.

Legacy Configuration Profiles
Traditional MDM configuration profiles do not provide a mechanism to enforce pluginkit extension states for third-party applications. While configuration profiles can define and enforce granular settings across Apple devices. The extension enablement state for third-party password managers is not exposed as a managed preference key and therefore cannot be controlled through a profile payload.

Jamf Pro’s Restricted Software Feature
While Jamf Pro’s Restricted Software feature could theoretically be used to block the Apple Passwords application — it allows administrators to prevent users or groups of users from accessing certain applications, kill the restricted process, and display a message to the user — this approach carries significant risk. Native Apple applications, such as Apple Passwords, are deeply integrated into macOS and iCloud Keychain, and blocking the binary directly can have unintended consequences on core macOS services. This approach is therefore not recommended for production environments.

Silence Apple Passwords & Enable 3rd Party Password Managers

For these reasons, direct script management via pluginkit is the preferred approach. This script uses launchctl asuser to execute privileged commands within the context of the logged-in user’s session, which is the only supported programmatic method for modifying pluginkit extension states on a managed macOS system. The script must be executed as root to invoke launchctl asuser, but all extension-related operations are delegated to the user session to ensure they are applied correctly.

Recurring Execution Required

This script must be deployed on a recurring schedule via your Mac systems’ MDM platform, like Jamf Pro, Intune, etc., rather than as a one-time execution. The pluginkit extension state is stored in a user-level cache that can be invalidated under the following conditions:

  • macOS system updates or security patches
  • Application updates to 1Password, Bitwarden, or Apple Passwords
  • Clearing of the pluginkit cache (pluginkit -f)
  • User logout/login cycles in some configurations

When the cache is invalidated, macOS may revert extension states back to their defaults — which restores Apple Passwords as the active autofill extension. It is recommended that this script be scheduled to run at a minimum on every login event or as a recurring daily policy to ensure the desired extension state is consistently enforced across all managed endpoints.

Usage

This script must be executed with root privileges via sudo. It is intended for deployment through an MDM platform (e.g., Jamf Pro) as a policy script or run manually by an administrator on a managed macOS endpoint.

sudo ./configure_password_manager_autofill.sh

Requirements

  • macOS 12 (Monterey) or later
  • A supported third-party password manager must be installed prior to execution (1Password 7, 1Password 8, or Bitwarden)
  • A user must be actively logged in to the console session at the time the script runs
  • Script must be executed as root

Behavior

Upon execution, the script will perform the following actions in order:

  1. Disable the Apple Passwords autofill extension via pluginkit
  2. Detect which supported third-party password manager is installed (1Password 7, 1Password 8, or Bitwarden)
  3. Enable the detected third-party password manager’s Safari autofill extension via pluginkit

All actions are logged to /var/log/PasswordManagerAutofill.log.

Notes

  • If no supported password manager is found, the script will exit cleanly with a warning logged
  • The script is safe to run multiple times; it checks the current extension state before making changes
  • Safari should be relaunched after the script runs for changes to take effect
#!/bin/bash
#
# Password Manager Autofill Enabler
#
# Version: 1.0.5
# Revised: 2026.03.04
#
# Enable autofill extensions for 3rd-party password managers (1Password, Bitwarden).
# Also disables Apple Passwords autofill extension. Must run as root so launchctl/pluginkit can reach the UI session.
# 
# Usage:
#   sudo ./password_manager_autofill_enabler.sh
#
# Copyright (c) 2026 University of Utah Student Computing Labs.
# All Rights Reserved.
#
# Permission to use, copy, modify, and distribute this software and
# its documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appears in all copies and
# that both that copyright notice and this permission notice appear
# in supporting documentation, and that the name of The University
# of Utah not be used in advertising or publicity pertaining to
# distribution of the software without specific, written prior
# permission. This software is supplied as is without expressed or
# implied warranties of any kind.
#

script_version="1.0.5"

### Root Check ###
if [[ $EUID -ne 0 ]]; then
    echo "ERROR: This script must be run as root (sudo)." >&2
    exit 1
fi

LOGGED_IN_USER=$( scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && ! /loginwindow/ { print $3 }' )
LOG_FILE="/var/log/PasswordManagerAutofill.log"
USER_UID=$(id -u "$LOGGED_IN_USER")

### App/Extension Mappings (bash 3 compatible) ###
APP_PATHS=(
    "/Applications/1Password 7 - Password Manager.app"
    "/Applications/1Password.app"
    "/Applications/Bitwarden.app"
)
APP_EXTENSIONS=(
    "com.agilebits.onepassword7-osx.7extension"
    "com.1password.1password.autofill"
    "com.bitwarden.desktop.safari"
)

# Apple Passwords extension to silence
APPLE_PASSWORDS_EXTENSION="com.apple.Passwords"

### Helpers ###
function logMe () {
    echo "$(/bin/date '+%Y-%m-%d %H:%M:%S'): ${1}" | tee -a "${LOG_FILE}"
}

function runAsUser () {
    launchctl asuser "$USER_UID" sudo -u "$LOGGED_IN_USER" "$@"
}

function checkForApp () {
    local app_path="$1"
    if [[ ! -d "${app_path}" ]]; then
        logMe "WARN: ${app_path} not installed — skipping."
        return 1
    fi
    logMe "INFO: Found ${app_path}"
    return 0
}

function enableExtension () {
    local extension="$1"
    logMe "Checking extension: ${extension}"

    local results
    results=$(runAsUser pluginkit -m | grep "${extension}")

    if [[ -z "$results" ]]; then
        logMe "WARN: Extension not found in pluginkit: ${extension} — skipping."
        return
    fi

    if [[ $(echo "$results" | awk '{print $1}') == "+" ]]; then
        logMe "INFO: ${extension} is already enabled."
    else
        logMe "INFO: Enabling ${extension}..."
        runAsUser pluginkit -e use -i "${extension}"
        logMe "INFO: ${extension} enabled."
    fi
}

function disableExtension () {
    local extension="$1"
    logMe "Checking extension to disable: ${extension}"

    local results
    results=$(runAsUser pluginkit -m | grep "${extension}")

    if [[ -z "$results" ]]; then
        logMe "WARN: Extension not found in pluginkit: ${extension} — skipping."
        return
    fi

    if [[ $(echo "$results" | awk '{print $1}') == "!" ]]; then
        logMe "INFO: ${extension} is already disabled."
    else
        logMe "INFO: Disabling ${extension}..."
        runAsUser pluginkit -e ignore -i "${extension}"
        logMe "INFO: ${extension} disabled."
    fi
}

### Main ###
logMe "===== Password Manager Autofill Enabler v${script_version} ====="
logMe "Running for user: ${LOGGED_IN_USER} (UID ${USER_UID})"

# Disable Apple Passwords autofill
logMe "--- Silencing Apple Passwords autofill ---"
disableExtension "${APPLE_PASSWORDS_EXTENSION}"

# Enable 3rd-party password manager extensions
logMe "--- Enabling 3rd-party password manager extensions ---"
for i in "${!APP_PATHS[@]}"; do
    app_path="${APP_PATHS[$i]}"
    extension_id="${APP_EXTENSIONS[$i]}"
    checkForApp "${app_path}" || continue
    enableExtension "${extension_id}"
done

logMe "===== Done ====="
No Comments

Leave a Reply