GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-137586: Replace 'osascript' with 'open' on macOS in webbrowser by secengjeff · Pull Request #146439 · python/cpython

Conversation

@secengjeff

@secengjeff secengjeff commented Mar 26, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Replaces MacOSXOSAScript (which constructs and executes AppleScript via osascript) with a new MacOS class that uses /usr/bin/open. MacOSXOSAScript is deprecated and scheduled for removal in Python 3.17.

Motivation

The previous PATH-lookup vulnerability with osascript was addressed in a separate PR. However, use of osascript remains a concern:

Usability: On managed enterprise Macs, EDR/MDM tools often monitor or restrict osascript due to its role in malware campaigns. When restrictions apply, webbrowser.open() breaks with no obvious connection to osascript, making the failure difficult to diagnose.

Security: osascript is a general-purpose scripting interpreter and a known Living-Off-the-Land binary. It was used on macOS in the Axios npm supply-chain attack (March 31, 2026). Opening a URL requires none of its scripting power. Using it unnecessarily increases the standard library's attack surface and keeps Python dependent on a tool security teams routinely flag.

Implementation

  • For http/https URLs with the default browser, calls /usr/bin/open <url> directly — macOS routes these to the registered browser.
  • For all other schemes (file://, etc.), uses /usr/bin/open -b <bundle-id> <url> so the URL is always passed to a browser rather than the OS file handler, preventing file injection attacks.
  • Default browser bundle ID is resolved from the LaunchServices plist (~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist). On fresh installs where the plist is absent, falls back to com.apple.Safari (macOS's built-in default), ensuring -b is always used.
  • Named browsers with known bundle IDs use -b; unknown names fall back to -a.

Changes

  • Lib/webbrowser.py:
    • New MacOS class using /usr/bin/open
    • _macos_default_browser_bundle_id() using plistlib (moved to top-level imports)
    • MacOSXOSAScript deprecated via warnings._deprecated(..., remove=(3, 17))
    • register("MacOSX", ...) retained as backward compatibility alias
    • Added bundle IDs for Opera, Edge, and Brave; registered all named browsers
    • Fixed builtins.open shadow: bare open() in module scope resolves to webbrowser.open(), causing infinite recursion; fixed with explicit builtins.open()
  • Lib/test/test_webbrowser.py: Tests for all new behaviour and deprecation warning
  • Doc/library/webbrowser.rst: Documentation updates, deprecated-removed:: next 3.17
  • Doc/deprecations/pending-removal-in-3.17.rst: Deprecation index entry for MacOSXOSAScript

Tested locally against Safari, Chrome, Firefox, Opera, Edge, and Brave with https, http, and file:// URLs.

References

  • Related issue: Security and usability improvement for webbrowser.open() on macOS: Replace osascript with /usr/bin/open #148472
  • Discussion: https://discuss.python.org/t/security-and-usability-improvement-for-webbrowser-open-on-macos-replace-osascript-with-usr-bin-open/106943
  • Original PATH issue: Use absolute paths when invoking built-in shell commands #137586
  • Issue: Use absolute paths when invoking built-in shell commands #137586

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
secengjeff added 3 commits March 25, 2026 18:31
@secengjeff
pythongh-137586: Add MacOSX browser class using /usr/bin/open, deprec…
00fa6c7
…ate MacOSXOSAScript

Add a new MacOSX class that opens URLs via subprocess.run(['/usr/bin/open', ...])
instead of piping AppleScript to osascript. For named browsers, /usr/bin/open -a
<name> is used; for the default browser, /usr/bin/open <url> defers directly to
the OS URL handler.

MacOSXOSAScript is deprecated with a DeprecationWarning pointing users to MacOSX.
register_standard_browsers() is updated to use MacOSX for all macOS registrations.

osascript is a general-purpose scripting interpreter that is routinely blocked on
managed endpoints due to its abuse potential, causing webbrowser.open() to fail
silently. /usr/bin/open is Apple's purpose-built URL-opening primitive and carries
no such restrictions. This also eliminates the PATH-injection vector in the existing
os.popen("osascript", "w") call.
@secengjeff
pythongh-137586: Add tests for MacOSX browser class and MacOSXOSAScri…
f697cd5
…pt deprecation

Add MacOSXTest covering default browser open, named browser open, and failure
case (non-zero returncode). Add MacOSXOSAScriptDeprecationTest verifying that
instantiating MacOSXOSAScript emits a DeprecationWarning. All tests mock
subprocess.run.
@secengjeff
pythongh-137586: Document MacOSXOSAScript deprecation in webbrowser docs
7781033
@bedevere-app

bedevere-app Bot commented Mar 26, 2026

Copy link
Copy Markdown

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@python-cla-bot

python-cla-bot Bot commented Mar 26, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot mentioned this pull request Mar 26, 2026
Use absolute paths when invoking built-in shell commands #137586
Closed
@bedevere-app bedevere-app Bot added the awaiting review label Mar 26, 2026
@secengjeff secengjeff mentioned this pull request Mar 26, 2026
gh-137586: Open external osascript program with absolute path #137584
Merged
@secengjeff secengjeff changed the title gh-137586: Replace MacOSXOSAScript with MacOSX on macOS, using /usr/bin/open gh-137586: Replace 'osascript' with 'open' on macOS Mar 26, 2026
secengjeff added 5 commits March 25, 2026 18:42
@secengjeff
pythongh-137586: Add NEWS entries for MacOSX webbrowser change
6066221
@secengjeff
pythongh-137586: Fix NEWS entry class references with ! prefix to sup…
d54293f
…press Sphinx lookup
@secengjeff
pythongh-137586: Fix MacOSXOSAScriptTest for MacOSX registration change
080197e
- Add test_default to MacOSXTest asserting webbrowser.get() returns MacOSX
- Remove test_default from MacOSXOSAScriptTest (no longer the registered default)
- Suppress DeprecationWarning in MacOSXOSAScriptTest setUp and test_explicit_browser
  using warnings.catch_warnings() so tests for OSAScript behaviour still run cleanly
- Add warnings import
@secengjeff
pythongh-137586: Use bundle IDs in MacOSX to prevent file injection v…
fdd6649
…ia OS handler

For non-http(s) URLs (e.g. file://), /usr/bin/open dispatches via the OS
file handler, which would launch an .app bundle rather than open it in a
browser. Fix this by routing non-http(s) URLs through the browser explicitly
using /usr/bin/open -b <bundle-id>.

Named browsers use a static bundle ID map (Chrome, Firefox, Safari, Chromium,
Opera, Edge). Unknown named browsers fall back to -a. For the default browser,
the bundle ID is resolved at runtime via the Objective-C runtime using
NSWorkspace.URLForApplicationToOpenURL, the same lookup MacOSXOSAScript
performed via AppleScript. Falls back to direct open if ctypes is unavailable.

http/https URLs with the default browser continue to use /usr/bin/open
directly, as macOS always routes these to the registered browser.
@secengjeff
pythongh-137586: Load AppKit before NSWorkspace lookup in _macos_defa…
8e1eef4
…ult_browser_bundle_id

NSWorkspace is an AppKit class and is not registered in the ObjC runtime
until AppKit is loaded. Without the explicit LoadLibrary call, objc_getClass
returns nil for NSWorkspace, causing the entire lookup to silently fall back
to /usr/bin/open without -b.
@vstinner vstinner changed the title gh-137586: Replace 'osascript' with 'open' on macOS gh-137586: Replace 'osascript' with 'open' on macOS in webbrowser Mar 27, 2026
gpshead
gpshead reviewed Apr 5, 2026
View reviewed changes
Comment thread Doc/library/webbrowser.rst Outdated
(4)
Only on iOS.

.. deprecated:: 3.14

@gpshead gpshead Apr 5, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3.15

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@hugovk hugovk Apr 6, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. deprecated:: 3.14
.. deprecated:: next

And precede this deprecated block with a versionadded for the new class, and move both after versionchanged:: 3.13 below.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@hugovk hugovk Apr 6, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the MacOSXOSAScripts in the table above need updating, and should we also add chrome and firefox (with note (3)) as also returning the new class?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@gpshead
gpshead requested a review from ned-deily April 5, 2026 22:51
@ned-deily
ned-deily requested review from a team and ronaldoussoren April 6, 2026 00:19
ronaldoussoren
ronaldoussoren requested changes Apr 6, 2026
View reviewed changes

@ronaldoussoren ronaldoussoren left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this PR.

The direct security issue can be fixed by changing the invocation of osascript to /usr/bin/osascript. Blocking osascript while allowing usage of Python is IMHO security theatre.

On modernist systems (macOS 10.15 or later) it is probably possible to just use NSWorkspace directly: it has all the moving peaces to implement what we need for webbrowser.open although I haven't thought through the implications of doing this yet. In particular, -[NSWorkpace openURLs:withApplicationAtURL:configuration:completionHandler:] is asynchronous which makes it harder to report errors.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/webbrowser.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot added awaiting changes and removed awaiting review labels Apr 6, 2026
@bedevere-app

bedevere-app Bot commented Apr 6, 2026

Copy link
Copy Markdown

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

hugovk
hugovk reviewed Apr 6, 2026
View reviewed changes
Comment thread Doc/library/webbrowser.rst Outdated
(4)
Only on iOS.

.. deprecated:: 3.14

@hugovk hugovk Apr 6, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. deprecated:: 3.14
.. deprecated:: next

And precede this deprecated block with a versionadded for the new class, and move both after versionchanged:: 3.13 below.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/webbrowser.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/webbrowser.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Doc/library/webbrowser.rst Outdated
(4)
Only on iOS.

.. deprecated:: 3.14

@hugovk hugovk Apr 6, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the MacOSXOSAScripts in the table above need updating, and should we also add chrome and firefox (with note (3)) as also returning the new class?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/webbrowser.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@merwok merwok added type-feature A feature request or enhancement OS-mac labels Apr 6, 2026
secengjeff and others added 4 commits April 6, 2026 09:22
@secengjeff @claude
pythongh-137586: Register chromium, opera, microsoft-edge in register…
e193626
…_standard_browsers on macOS

These browsers were present in MacOSX._BUNDLE_IDS but not registered,
causing webbrowser.get("opera") etc. to raise Error: could not locate
runnable browser.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@secengjeff
pythongh-137586: Fix Microsoft Edge bundle ID on macOS (com.microsoft…
98dd1d8
….edgemac)
@secengjeff
pythongh-137586: Replace _macos_default_browser_bundle_id with plistl…
bdfc2e6
…ib to address memory and os.fork() concerns
@secengjeff
pythongh-137586: Rename MacOSX to MacOS
614078f
secengjeff and others added 6 commits April 22, 2026 19:37
@secengjeff @hugovk
Update Misc/NEWS.d/next/Security/2026-03-26-01-42-15.gh-issue-137586.…
e4e89f1
…j3SkOm.rst

Co-authored-by: Hugo van Kemenade <[email protected]>
@secengjeff @hugovk
Update Doc/library/webbrowser.rst
b513903
Co-authored-by: Hugo van Kemenade <[email protected]>
@secengjeff @hugovk
Update Doc/library/webbrowser.rst
aacbceb
Co-authored-by: Hugo van Kemenade <[email protected]>
@secengjeff
pythongh-137586: Fix MacOS plist fallback, builtins.open shadow, add …
a6d76d6
…Brave

Return 'com.apple.Safari' instead of None when the LaunchServices plist is
absent (fresh installs never write it). None caused the non-http branch to
fall back to bare '/usr/bin/open <url>', bypassing -b and triggering the OS
file handler. Addresses gpshead's CHANGES_REQUESTED.

Fix infinite recursion: webbrowser's module-level open() shadowed
builtins.open, so open(plist, 'rb') called webbrowser.open() recursively
on every non-http/https URL. Use builtins.open() explicitly.

Narrow 'except Exception' to '(OSError, KeyError, ValueError)'. Addresses
hugovk's review comment.

Add 'brave browser': 'com.brave.Browser' to _BUNDLE_IDS and register it
so webbrowser.get('brave') works and Brave uses precise -b dispatch instead
of the name-based -a fallback.

Tested locally against Safari, Chrome, Firefox, Opera, Edge, and Brave
with https, http, and file:// URLs. 29/29 checks pass.
@secengjeff
Merge branch 'main' into pythongh-137586-macosx-open
5a4fdad
@secengjeff
pythongh-137586: Address hugovk review comments
de9ec77
Move plistlib to top-level imports alongside the existing import block.
Remove os from the inline import inside _macos_default_browser_bundle_id
as it is already imported at module level. Remove the stale
'# Maintained by Georg Brandl.' comment.

Replace manual warnings.warn() in MacOSXOSAScript.__init__ with
warnings._deprecated("webbrowser.MacOSXOSAScript", remove=(3, 17)).

Change 'deprecated:: next' to 'deprecated-removed:: next 3.17' in
Doc/library/webbrowser.rst. Add MacOSXOSAScript to
Doc/deprecations/pending-removal-in-3.17.rst.

Add register("MacOSX", None, MacOS('default')) as a backward
compatibility alias so webbrowser.get("MacOSX") continues to work.
@secengjeff

secengjeff commented Apr 23, 2026

Copy link
Copy Markdown
Contributor Author

I have made the requested changes; please review again

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot added awaiting change review and removed awaiting changes labels Apr 23, 2026
@bedevere-app

bedevere-app Bot commented Apr 23, 2026

Copy link
Copy Markdown

Thanks for making the requested changes!

@ronaldoussoren, @gpshead: please review the changes made to this pull request.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app
bedevere-app Bot requested a review from gpshead April 23, 2026 03:38
@secengjeff
secengjeff requested a review from hugovk April 23, 2026 03:38
@gpshead
lazy import plistlib
6ddf67f
gpshead
gpshead approved these changes Apr 23, 2026
View reviewed changes
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting change review labels Apr 23, 2026
hugovk
hugovk approved these changes Apr 23, 2026
View reviewed changes

@hugovk hugovk left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, just some little nits.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Doc/deprecations/pending-removal-in-3.17.rst
* :mod:`webbrowser`:

- :class:`!webbrowser.MacOSXOSAScript` is deprecated in favour of
:class:`!webbrowser.MacOS`. (:gh:`137586`)

@hugovk hugovk Apr 23, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please list alphabetically, after typing

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/webbrowser.py

import builtins # because we override open
import os
lazy import plistlib

@hugovk hugovk Apr 23, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this after the regular import block, so directly after import threading.

(This is the style being adopted by isort and Ruff.)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Misc/NEWS.d/next/Library/2026-03-26-01-42-20.gh-issue-137586.KmHRwR.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/test/test_webbrowser.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@hugovk

hugovk commented Apr 23, 2026

Copy link
Copy Markdown
Member

Oh, and please add to https://docs.python.org/3.15/whatsnew/3.15.html

We can have one entry under "Improved modules" and another under "New deprecations", and can largely be the same as the two NEWS entries.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@secengjeff
pythongh-137586: Address hugovk post-approval concerns
f874d67
Move webbrowser entry in Doc/deprecations/pending-removal-in-3.17.rst
to after typing, to maintain alphabetical order.

Move import plistlib to after import threading, per isort/Ruff style
of placing stdlib imports after the main import block.

Fix :class:`!MacOSX` -> :class:`!MacOS` in the Library NEWS entry.

Remove extra blank line in MacOSXOSAScriptTest.mock_popen.

Add webbrowser entries to Doc/whatsnew/3.15.rst: one under "Improved
modules" describing the new MacOS class, and one under "New
deprecations" for MacOSXOSAScript scheduled removal in 3.17.
@secengjeff
secengjeff requested a review from AA-Turner as a code owner April 23, 2026 14:11
secengjeff and others added 2 commits April 23, 2026 07:16
@secengjeff
pythongh-137586: Fix Sphinx ref.class warnings in whatsnew/3.15.rst
3b390bb
Use :class:`!webbrowser.MacOS` and :class:`!webbrowser.MacOSXOSAScript`
with the ! prefix to suppress cross-reference lookup for classes not yet
present in upstream.
@hugovk
Merge branch 'main' into pythongh-137586-macosx-open
21b5499
@read-the-docs-community

read-the-docs-community Bot commented May 6, 2026

Copy link
Copy Markdown

Documentation build overview

📚 cpython-previews | 🛠️ Build #32562113 | 📁 Comparing 21b5499 against main (8bf99ae)

  🔍 Preview build  

89 files changed · + 2 added · ± 87 modified

+ Added

  • c-api/sentinel.html
  • c-api/slots.html

± Modified

  • glossary.html
  • c-api/concrete.html
  • c-api/extension-modules.html
  • c-api/index.html
  • c-api/lifecycle.html
  • c-api/module.html
  • c-api/perfmaps.html
  • c-api/stable.html
  • c-api/synchronization.html
  • c-api/type.html
  • and 77 more...
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@hugovk
hugovk merged commit aeb02ac into python:main May 6, 2026
52 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the awaiting merge label May 6, 2026
@hugovk

hugovk commented May 6, 2026

Copy link
Copy Markdown
Member

Thank you!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@merwok

merwok commented May 6, 2026

Copy link
Copy Markdown
Member

A bot is credited as co-author in the commit. Was that wanted?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@florentx florentx mentioned this pull request May 26, 2026
Python 3.14 webbrowser regression when launching vscode:// URI on macOS #149454
Open
@donbarbos donbarbos mentioned this pull request Aug 22, 2026
[webbrowser] Add MacOS and deprecated MacOSXOSAScript python/typeshed#16287
Merged
@savannahostrowski savannahostrowski mentioned this pull request Oct 21, 2026
Remove outdated argparse maintainer comment #160120
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@gpshead gpshead gpshead approved these changes
@hugovk hugovk hugovk approved these changes
@ned-deily ned-deily Awaiting requested review from ned-deily
@ronaldoussoren ronaldoussoren Awaiting requested review from ronaldoussoren
@AA-Turner AA-Turner Awaiting requested review from AA-Turner AA-Turner is a code owner

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

OS-mac type-feature A feature request or enhancement

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

5 participants

@secengjeff @hugovk @merwok @gpshead @ronaldoussoren
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.