Skip to content

fix: bound icon cache file reads#1

Merged
shiquda merged 2 commits intomasterfrom
codex/fix-local-denial-of-service-vulnerability
Mar 23, 2026
Merged

fix: bound icon cache file reads#1
shiquda merged 2 commits intomasterfrom
codex/fix-local-denial-of-service-vulnerability

Conversation

@shiquda
Copy link
Owner

@shiquda shiquda commented Mar 23, 2026

Motivation

  • LoadIconBytes previously used File.ReadAllBytes on files in the user-writable icon cache with no size checks, allowing a local attacker or corrupted cache to place an oversized file that could exhaust memory and cause a denial-of-service.
  • The change protects icon warm-up and cache persistence paths by validating sizes before reading or writing disk cache entries.

Description

  • Add a MaxCachedIconBytes constant (1 MiB) and use it to bound cached icon sizes.
  • In LoadIconBytes check the FileInfo.Length before reading and log & skip any cached files that are oversized or empty.
  • In TryPersistIconBytes refuse to write icon blobs larger than MaxCachedIconBytes to avoid populating the cache with oversized files.

Testing

  • Attempted dotnet build inputor.sln but the container does not have the .NET SDK installed, so the build could not be executed (dotnet: command not found).
  • Attempted dotnet run --project src/inputor.WinUI/inputor.WinUI.csproj -- --count-sample "Hello世界" but it was blocked for the same reason; no automated tests were run because the repository contains no test project.

Codex Task

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11156fcb32

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +337 to +340
if (cacheFileInfo.Length > MaxCachedIconBytes)
{
StartupDiagnostics.Log($"LoadIconBytes ignored oversized cached icon for {processName}: {cacheFileInfo.Length} bytes.");
return null;

Choose a reason for hiding this comment

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

P2 Badge Regenerate icons instead of bailing out on oversized cache files

Returning here skips the executable-extraction fallback later in LoadIconBytes, so any oversized cache entry (and the zero-byte case just above) now leaves that app with no icon until the user manually clears %LocalAppData%\inputor. This is easy to hit with a partially written cache file or with icons cached before the new 1 MiB limit was introduced; before this change those cases still fell through to ExtractAssociatedIcon and rebuilt the cache.

Useful? React with 👍 / 👎.

return null;
}

var diskBytes = File.ReadAllBytes(cacheFilePath);

Choose a reason for hiding this comment

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

P2 Badge Bound the icon read itself, not only the cached length check

This ReadAllBytes call still reads from a user-writable path after the size check happened on a separate FileInfo, so another local process can replace or grow the file between the two operations and force an unbounded allocation anyway. Because the commit’s goal is to prevent cache-file DoS, the read needs to stay on the same open handle and stop after MaxCachedIconBytes instead of reopening the path here.

Useful? React with 👍 / 👎.

@shiquda shiquda merged commit 2b77b9d into master Mar 23, 2026
2 checks passed
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 658c0bf6da

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

private static void TryPersistIconBytes(string? cacheFilePath, byte[] iconBytes, int generation)
{
if (cacheFilePath is null || iconBytes.Length == 0 || generation != IconCacheGeneration)
if (cacheFilePath is null || iconBytes.Length == 0 || iconBytes.Length > MaxCachedIconBytes || generation != IconCacheGeneration)

Choose a reason for hiding this comment

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

P2 Badge Cache a bounded version of oversized extracted icons

When iconBytes.Length > MaxCachedIconBytes, this guard skips writing anything to disk, but LoadIconBytes can only regenerate an icon from Process.GetProcessesByName(...) while that app is currently running. For any executable whose extracted PNG is larger than 1 MiB, the icon will appear during the current session but disappear after restart (or whenever the process is no longer running), so historical app rows permanently fall back to the generic glyph. If the intent is to bound the cache, we still need to persist a downsized/re-encoded icon instead of dropping the cache entry entirely.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant