automating-chrome — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited automating-chrome (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
JXA/AppleScript browser automation is legacy. JavaScript injection is disabled by default in modern Chrome. Modern alternatives: Selenium/ChromeDriver, Puppeteer, PyXA.
Related Skills: web-browser-automation, automating-mac-apps
PyXA Installation: See automating-mac-apps skill (PyXA Installation section).
Security Note: JavaScript injection via AppleScript is disabled by default in Chrome. Enable via: View → Developer → Allow JavaScript from Apple Events (not recommended for production use).
execute() runs JavaScript in page context but doesn't reliably return values—use tunneling patterns (save to clipboard/localStorage) for data extraction instead.⚠️ Security Warning: The tunneling approach (clipboard/localStorage) can expose sensitive data. Use modern APIs for production automation.
execute() doesn't return JavaScript results directly, work around this by having your injected script save data to accessible locations like the system clipboard (navigator.clipboard.writeText()) or localStorage (localStorage.setItem()). Then retrieve the data in your JXA script using system commands or by reading back from localStorage via another execute() call.1) Discover dictionary terms in Script Editor (Chrome or target browser). 2) Prototype minimal AppleScript commands in target browser. 3) Port to JXA and add defensive checks:
chrome.running()4) Use batch URL reads and reverse-order deletes for tab operations. 5) Use tunneling patterns for DOM data extraction. 6) Validate results: Log tab counts, URLs, or extracted data to confirm operations succeeded.
Open new tab and navigate:
const chrome = Application('Google Chrome');
chrome.windows[0].tabs.push(chrome.Tab());
chrome.windows[0].tabs[chrome.windows[0].tabs.length - 1].url = 'https://example.com';Execute JavaScript in current tab:
const result = chrome.execute({javascript: 'document.title'});
// Note: execute() runs JS but doesn't reliably return valuesBatch close tabs (reverse order):
const tabs = chrome.windows[0].tabs;
for (let i = tabs.length - 1; i >= 0; i--) {
if (tabs[i].url().includes('unwanted')) {
tabs[i].close();
}
}Extract page data via tunneling:
// Inject script to save title to localStorage
chrome.execute({javascript: 'localStorage.setItem("pageTitle", document.title)'});
// Retrieve via another execute call
chrome.execute({javascript: 'console.log(localStorage.getItem("pageTitle"))'});Check browser permissions:
try {
const chrome = Application('Google Chrome');
chrome.windows[0].tabs[0].url(); // Test access
console.log('Permissions OK');
} catch (error) {
console.log('Permission error:', error.message);
}For production Chrome automation, see the web-browser-automation skill for comprehensive guides covering:
Quick PyXA Example (see web-browser-automation skill for details):
import PyXA
# Launch Chrome and navigate
chrome = PyXA.Application("Google Chrome")
chrome.activate()
chrome.open_location("https://example.com")
# Get current tab info
current_tab = chrome.current_tab()
print(f"Page title: {current_tab.title()}")
print(f"Current URL: {current_tab.url()}")from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from AppKit import NSWorkspace
# Configure Chrome options
options = Options()
options.add_argument("--remote-debugging-port=9222")
options.add_argument('--headless=new') # Modern headless mode
# Launch Chrome with Selenium (automatic ChromeDriver management)
driver = webdriver.Chrome(options=options)
driver.get('https://example.com')
# macOS integration via PyObjC
workspace = NSWorkspace.sharedWorkspace()
frontmost_app = workspace.frontmostApplication()
print(f"Frontmost app: {frontmost_app.localizedName()}")
print(f"Page title: {driver.title}")
driver.quit()# Install Selenium (latest: 4.38.0)
pip install selenium
# ChromeDriver is automatically managed by Selenium Manager (v4.11+)
# No manual download needed - compatible version downloaded automatically
# Basic Python example
from selenium import webdriver
driver = webdriver.Chrome() # Automatic ChromeDriver management
driver.get('https://example.com')
print(driver.title)
driver.quit()Advanced Configuration:
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument('--headless=new') # Modern headless mode (required)
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome(options=options)
driver.get('https://example.com')
print(f"Page title: {driver.title}")
driver.quit()Manual ChromeDriver Setup (for specific versions):
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
# Download from https://googlechromelabs.github.io/chromedriver/
# Match major version with your Chrome installation
service = Service(executable_path='/path/to/chromedriver')
options = Options()
driver = webdriver.Chrome(service=service, options=options)Note: Selenium 4.11+ automatically downloads compatible ChromeDriver. Manual setup only needed for specific version requirements or CI/CD environments.
# Install Puppeteer (latest: 24.35.0)
npm install puppeteer
# Bundles compatible Chrome automaticallyconst puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: 'new' // Modern headless mode (required in v24+)
});
const page = await browser.newPage();
await page.goto('https://example.com');
const title = await page.title();
console.log(title);
await browser.close();
})();Advanced Puppeteer Configuration:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: 'new',
args: ['--no-sandbox', '--disable-dev-shm-usage']
});
const page = await browser.newPage();
// Set viewport
await page.setViewport({ width: 1280, height: 720 });
await page.goto('https://example.com');
// Wait for element and interact
await page.waitForSelector('h1');
const title = await page.title();
console.log(`Page title: ${title}`);
await browser.close();
})();// WebSocket connection to CDP
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:9222/devtools/page/{page-id}');
// Send CDP commands
ws.send(JSON.stringify({
id: 1,
method: 'Runtime.evaluate',
params: { expression: 'document.title' }
}));Setup Requirements:
npm install puppeteer--remote-debugging-port=9222chrome.running() returns trueautomating-chrome/references/chrome-basics.mdautomating-chrome/references/chrome-recipes.mdautomating-chrome/references/chrome-advanced.mdautomating-chrome/references/chrome-dictionary.mdautomating-chrome/references/chromium-browser-names.mdautomating-chrome/references/chrome-form-automation.mdRelated Skills for Modern Chrome Automation:
web-browser-automation: Complete guide for Chrome, Edge, Brave, and Arc automationautomating-mac-apps: PyXA fundamentals and conversion guides~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.