Skip to content

Fix SonarCloud critical vulnerabilities and bugs#3260

Open
eran132 wants to merge 2 commits intomRemoteNG:v1.78.2-devfrom
eran132:fix/sonarcloud-vulnerabilities-and-bugs
Open

Fix SonarCloud critical vulnerabilities and bugs#3260
eran132 wants to merge 2 commits intomRemoteNG:v1.78.2-devfrom
eran132:fix/sonarcloud-vulnerabilities-and-bugs

Conversation

@eran132
Copy link
Copy Markdown

@eran132 eran132 commented Apr 7, 2026

Summary

Fix all CRITICAL vulnerabilities and bugs flagged by SonarCloud on the v1.78.2-dev branch. These issues affect the project's security and reliability ratings (currently both D).

Changes

4 CRITICAL Security Vulnerabilities fixed:

  • PuttyBase.cs: Replace Path.GetTempFileName() with Path.Combine(GetTempPath(), GetRandomFileName()) — insecure temp file creation (S5445, 2 instances)
  • PasswordstateInterface.cs: Specify 2048-bit key size for RSACryptoServiceProvider — default key size too small (S4426)
  • SecretServerInterface.cs: Same RSA key size fix (S4426)

1 MAJOR CI Vulnerability fixed:

  • Build_mR-NB.yml: Move contents: write permission from workflow level to job level — follows least-privilege principle (S8233)

2 CRITICAL Bugs fixed:

  • ToolTipControl.cs: HasBorder setter now assigns hasBorder backing field after updating window style (S4275)
  • ToolTipControl.cs: Font getter returns backing field instead of re-reading from native handle (S4275)

Impact

These fixes should improve the branch quality gate from ERROR → OK:

  • Security Rating: D → A
  • Reliability Rating: D → A

Test plan

  • Verify PuTTY connections with external credential providers still work
  • Verify ToolTipControl border and font behavior unchanged
  • Verify CI workflow permissions are sufficient for releases

🤖 Generated with Claude Code

Security fixes (4 CRITICAL vulnerabilities):
- PuttyBase.cs: Replace insecure Path.GetTempFileName() with
  Path.Combine(GetTempPath(), GetRandomFileName()) (S5445, 2 instances)
- PasswordstateInterface.cs: Specify 2048-bit key size for
  RSACryptoServiceProvider (S4426)
- SecretServerInterface.cs: Specify 2048-bit key size for
  RSACryptoServiceProvider (S4426)

CI fix (1 MAJOR vulnerability):
- Build_mR-NB.yml: Move write permission from workflow level
  to job level (S8233)

Bug fixes (2 CRITICAL bugs):
- ToolTipControl.cs: HasBorder setter now assigns backing field
  hasBorder after updating window style (S4275)
- ToolTipControl.cs: Font getter returns backing field instead
  of re-reading from native handle, ensuring consistency (S4275)

These fixes address all CRITICAL/BLOCKER issues on the v1.78.2-dev
branch, improving reliability rating from D to A and security
rating from D to A.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 7, 2026 14:04
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Fix SonarCloud critical vulnerabilities and bugs

🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Fix 4 CRITICAL security vulnerabilities in RSA key generation and temp file handling
• Fix 2 CRITICAL bugs in ToolTipControl property accessors
• Improve CI/CD workflow security by applying least-privilege principle
Diagram
flowchart LR
  A["Security Issues<br/>RSA & Temp Files"] -->|Fix key size| B["PasswordstateInterface<br/>SecretServerInterface"]
  A -->|Replace insecure API| C["PuttyBase"]
  D["Bug Issues<br/>ToolTipControl"] -->|Fix setter| E["HasBorder property"]
  D -->|Fix getter| F["Font property"]
  G["CI Vulnerability<br/>Permissions"] -->|Move to job level| H["Build_mR-NB.yml"]
  B --> I["Improved Security Rating"]
  C --> I
  E --> J["Improved Reliability Rating"]
  F --> J
  H --> K["Least-Privilege Access"]
Loading

Grey Divider

File Changes

1. ExternalConnectors/CPS/PasswordstateInterface.cs 🐞 Bug fix +1/-1

Add explicit RSA key size specification

• Specify 2048-bit key size for RSACryptoServiceProvider constructor (S4426)
• Ensures minimum secure RSA key length instead of using default

ExternalConnectors/CPS/PasswordstateInterface.cs


2. ExternalConnectors/DSS/SecretServerInterface.cs 🐞 Bug fix +1/-1

Add explicit RSA key size specification

• Specify 2048-bit key size for RSACryptoServiceProvider constructor (S4426)
• Ensures minimum secure RSA key length instead of using default

ExternalConnectors/DSS/SecretServerInterface.cs


3. ObjectListView/SubControls/ToolTipControl.cs 🐞 Bug fix +2/-5

Fix property accessor backing field assignments

• Fix HasBorder setter to assign hasBorder backing field after updating window style (S4275)
• Fix Font getter to return cached backing field instead of re-reading from native handle (S4275)
• Ensures property consistency and prevents redundant native calls

ObjectListView/SubControls/ToolTipControl.cs


View more (2)
4. mRemoteNG/Connection/Protocol/PuttyBase.cs 🐞 Bug fix +2/-2

Replace insecure temp file creation API

• Replace insecure Path.GetTempFileName() with `Path.Combine(Path.GetTempPath(),
 Path.GetRandomFileName())` in 2 locations (S5445)
• Fixes insecure temporary file creation vulnerability in both Delinea SecretServer and Clickstudios
 PasswordState credential provider paths

mRemoteNG/Connection/Protocol/PuttyBase.cs


5. .github/workflows/Build_mR-NB.yml ⚙️ Configuration changes +2/-3

Apply least-privilege permission principle

• Move contents: write permission from workflow level to job level (S8233)
• Applies least-privilege principle by restricting permission scope to only the job that needs it

.github/workflows/Build_mR-NB.yml


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 7, 2026

Code Review by Qodo

🐞 Bugs (1)   📘 Rule violations (0)   📎 Requirement gaps (0)   🎨 UX Issues (0)
🐞\ ⛨ Security (1)

Grey Divider


Action required

1. Non-atomic temp key file 🐞
Description
PuttyBase.Connect() now generates a temp private-key path via GetRandomFileName() and then writes it
with File.WriteAllText(), which is non-atomic and can overwrite/delete an existing file if the name
already exists or is pre-created. This can clobber unrelated files and weakens the safety of
handling sensitive private-key material.
Code

mRemoteNG/Connection/Protocol/PuttyBase.cs[R124-126]

+                                    optionalTemporaryPrivateKeyPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                                    File.WriteAllText(optionalTemporaryPrivateKeyPath, privatekey);
                                    FileInfo fileInfo = new(optionalTemporaryPrivateKeyPath)
Evidence
The temp key file path is generated without creating the file atomically, then written via
File.WriteAllText() (two occurrences). In the finally block, the code unconditionally deletes the
same path—so if an existing file was overwritten or the path was pre-created, the cleanup can delete
the wrong file.

mRemoteNG/Connection/Protocol/PuttyBase.cs[116-151]
mRemoteNG/Connection/Protocol/PuttyBase.cs[399-407]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`PuttyBase.Connect()` creates a temporary private-key file by generating a random name (`Path.GetRandomFileName()`) and then writing with `File.WriteAllText()`. This is not an exclusive/atomic create and can overwrite an existing file (collision or pre-creation), and the `finally` block then deletes whatever exists at that path.

### Issue Context
This temp file contains SSH private key material and is passed to PuTTY via `-i`, so we still need a real filesystem path. The key requirement is to create the file *atomically* (no overwrite) and only delete the file that we created.

### Fix Focus Areas
- mRemoteNG/Connection/Protocol/PuttyBase.cs[116-151]
- mRemoteNG/Connection/Protocol/PuttyBase.cs[399-407]

### Suggested fix approach
- Replace `Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())` + `File.WriteAllText(...)` with an atomic create:
 - Generate a candidate path (optionally add `.ppk` extension for clarity).
 - Open with `new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.None)` and write the content via `StreamWriter`.
 - Retry on `IOException` for name collisions.
- Track a boolean like `tempKeyFileCreated` and only delete the file in `finally` if creation succeeded.
- (Optional hardening) Apply restrictive ACLs on Windows so only the current user can read the temp key file.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Apr 7, 2026

Comment on lines +124 to 126
optionalTemporaryPrivateKeyPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
File.WriteAllText(optionalTemporaryPrivateKeyPath, privatekey);
FileInfo fileInfo = new(optionalTemporaryPrivateKeyPath)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Non-atomic temp key file 🐞 Bug ⛨ Security

PuttyBase.Connect() now generates a temp private-key path via GetRandomFileName() and then writes it
with File.WriteAllText(), which is non-atomic and can overwrite/delete an existing file if the name
already exists or is pre-created. This can clobber unrelated files and weakens the safety of
handling sensitive private-key material.
Agent Prompt
### Issue description
`PuttyBase.Connect()` creates a temporary private-key file by generating a random name (`Path.GetRandomFileName()`) and then writing with `File.WriteAllText()`. This is not an exclusive/atomic create and can overwrite an existing file (collision or pre-creation), and the `finally` block then deletes whatever exists at that path.

### Issue Context
This temp file contains SSH private key material and is passed to PuTTY via `-i`, so we still need a real filesystem path. The key requirement is to create the file *atomically* (no overwrite) and only delete the file that we created.

### Fix Focus Areas
- mRemoteNG/Connection/Protocol/PuttyBase.cs[116-151]
- mRemoteNG/Connection/Protocol/PuttyBase.cs[399-407]

### Suggested fix approach
- Replace `Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())` + `File.WriteAllText(...)` with an atomic create:
  - Generate a candidate path (optionally add `.ppk` extension for clarity).
  - Open with `new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.None)` and write the content via `StreamWriter`.
  - Retry on `IOException` for name collisions.
- Track a boolean like `tempKeyFileCreated` and only delete the file in `finally` if creation succeeded.
- (Optional hardening) Apply restrictive ACLs on Windows so only the current user can read the temp key file.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Addresses SonarCloud-reported critical security and reliability findings in mRemoteNG by hardening temp file creation, updating cryptography defaults, tightening GitHub Actions permissions, and fixing tooltip control state bugs.

Changes:

  • Replace insecure temporary file creation for extracted PuTTY private keys.
  • Enforce stronger RSA settings in external connector key-import helpers.
  • Scope GitHub Actions contents: write permission down from workflow-level to job-level; fix tooltip border/font property behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
ObjectListView/SubControls/ToolTipControl.cs Fixes tooltip HasBorder backing field update and makes Font getter return the cached font.
mRemoteNG/Connection/Protocol/PuttyBase.cs Changes how temporary private key files are named/created before launching PuTTY.
ExternalConnectors/DSS/SecretServerInterface.cs Updates RSA provider construction in PEM import helper.
ExternalConnectors/CPS/PasswordstateInterface.cs Updates RSA provider construction in PEM import helper.
.github/workflows/Build_mR-NB.yml Moves contents: write permission from workflow to job scope.

Comment on lines +124 to 126
optionalTemporaryPrivateKeyPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
File.WriteAllText(optionalTemporaryPrivateKeyPath, privatekey);
FileInfo fileInfo = new(optionalTemporaryPrivateKeyPath)
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The temp key file is now created via Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()) but then written with File.WriteAllText(...), which will overwrite an existing file if it already exists. That reintroduces a TOCTOU/symlink/hardlink risk and doesn’t guarantee exclusive creation. Prefer creating the file with FileMode.CreateNew (retrying on collision) and writing to the opened stream, so the temp file is created atomically and cannot be pre-created/replaced by another process.

Copilot uses AI. Check for mistakes.
Comment on lines +242 to 243
RSACryptoServiceProvider rsa = new(2048);
rsa.ImportParameters(rsaParams);
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

new RSACryptoServiceProvider(2048) generates a new 2048-bit keypair before you immediately import the provided PEM parameters. Besides unnecessary work, it may fail if the imported key is a different size (e.g., 4096-bit). Since this method is importing an existing key, consider constructing the provider without forcing a generated key size and instead validate after import that KeySize >= 2048 (rejecting weaker keys explicitly).

Suggested change
RSACryptoServiceProvider rsa = new(2048);
rsa.ImportParameters(rsaParams);
RSACryptoServiceProvider rsa = new();
rsa.ImportParameters(rsaParams);
if (rsa.KeySize < 2048)
{
rsa.Dispose();
throw new CryptographicException("RSA private key size must be at least 2048 bits.");
}

Copilot uses AI. Check for mistakes.
Comment thread ExternalConnectors/CPS/PasswordstateInterface.cs Outdated
Comment on lines 14 to 18
jobs:
NB-Build-and-Release:
permissions:
contents: write
strategy:
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

Workflow-level contents: write was removed and only the NB-Build-and-Release job now has it. However, Create-Combined-Release uses softprops/action-gh-release to create a tag/release and upload assets, which also requires contents: write. Add permissions: { contents: write } to Create-Combined-Release (or move the permission to just the jobs that need it) to avoid release failures.

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants