Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -381,10 +381,13 @@ final class ActionExecutor: ActionExecuting {
private func mdfindApp(name: String, timeout: UInt64 = 2_000_000_000) async -> URL? {
let process = Process()
process.executableURL = URL(fileURLWithPath: "/usr/bin/mdfind")
// Escape single quotes in the app name to prevent breaking the mdfind query
let sanitizedName = name.replacingOccurrences(of: "'", with: "'\\''")
// Use double quotes for the display-name value so we only need to escape
// double quotes. Process.arguments bypasses the shell, so shell-style
// single-quote escaping (e.g. '\'') would be passed raw to mdfind and
// break Spotlight query parsing.
let sanitizedName = name.replacingOccurrences(of: "\"", with: "\\\"")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Missing backslash escaping in mdfind query allows malformed Spotlight queries

The sanitization on line 388 only escapes double quotes but not backslashes. Since mdfind's Spotlight query parser treats \ as an escape character inside double-quoted strings, an app name containing a backslash will produce a malformed query.

Root Cause and Example

If name is foo\ (contains a literal backslash), the sanitized name is still foo\ (no replacement occurs), and the query becomes:

kMDItemKind == 'Application' && kMDItemDisplayName == "foo\"

Here \" is interpreted by mdfind as an escaped double quote, so the string literal is never terminated and the query is malformed. This causes mdfind to fail (exit non-zero), and the function returns nil.

More critically, a name like foo\"bar would have its " escaped to \", producing foo\\\"bar in the query — but the original backslash isn't escaped, so mdfind sees foo\"bar where \" is an escaped quote, breaking the intended string boundary.

Backslashes must be escaped before double quotes to ensure correct nesting:

let sanitizedName = name
    .replacingOccurrences(of: "\\", with: "\\\\")
    .replacingOccurrences(of: "\"", with: "\\\"")

Impact: While app names with backslashes are extremely rare on macOS, this is an incomplete fix for the escaping problem the PR is trying to solve. The function degrades gracefully (returns nil), so the impact is limited to a failed lookup rather than a crash.

Suggested change
let sanitizedName = name.replacingOccurrences(of: "\"", with: "\\\"")
let sanitizedName = name.replacingOccurrences(of: "\\", with: "\\\\").replacingOccurrences(of: "\"", with: "\\\"")
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

process.arguments = [
"kMDItemKind == 'Application' && kMDItemDisplayName == '\(sanitizedName)'"
"kMDItemKind == 'Application' && kMDItemDisplayName == \"\(sanitizedName)\""
]

let stdout = Pipe()
Expand Down
Loading