-
Notifications
You must be signed in to change notification settings - Fork 1
Implement DevSecOps3 demo page with GHAS v3 features #99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Add new DevSecOps3.cshtml page with latest GitHub Advanced Security content - Implement DevSecOps3Model with intentionally insecure code for demo purposes - ReDoS vulnerable regex pattern - Log forging vulnerabilities - Hardcoded credentials and secrets - SQL injection potential - Excessive error information disclosure - Update package references to exact versions specified: - System.Text.Json 8.0.4 - Microsoft.Data.SqlClient 5.0.2 - Newtonsoft.Json 12.0.2 - Add navigation links to DevSecOps3 page in layout and index - Add ILogger implementation for backend code - Build successful with intentional vulnerability warnings for GHAS demo Addresses issue #84
Dependency ReviewThe following issues were found:
Vulnerabilitiessrc/webapp01/webapp01.csproj
Only included vulnerabilities with severity moderate or higher. OpenSSF Scorecard
Scanned Files
|
catch (Exception ex) | ||
{ | ||
// SECURITY ISSUE: Exposing exception details in logs without sanitization | ||
_logger.LogError("Regex processing failed: {Exception}", ex.ToString()); | ||
TempData["RegexError"] = $"Regex processing failed: {ex.Message}"; | ||
return RedirectToPage(); | ||
} |
Check notice
Code scanning / CodeQL
Generic catch clause Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 25 days ago
To fix the problem, the catch clause in the OnPostTestRegex
method should be narrowed to only catch exceptions that are expected from regex operations. The most common exceptions thrown by Regex.IsMatch
are RegexMatchTimeoutException
(if a timeout is set) and ArgumentException
(for invalid patterns). Since the code does not set a timeout, RegexMatchTimeoutException
is less likely, but ArgumentException
is possible. If you want to be robust, you can catch both. Any other unexpected exceptions should be allowed to propagate, or optionally caught in a separate generic catch block that logs and rethrows or handles them differently.
Steps:
- Replace
catch (Exception ex)
withcatch (ArgumentException ex)
and optionallycatch (RegexMatchTimeoutException ex)
. - Optionally, add a generic catch block after the specific ones to log unexpected errors without exposing details to the user.
- Only edit the catch clause in the
OnPostTestRegex
method (lines 41-47). - No new imports are needed, as
ArgumentException
andRegexMatchTimeoutException
are part of the standard library.
-
Copy modified line R41 -
Copy modified lines R43-R45 -
Copy modified lines R48-R54
@@ -38,13 +38,20 @@ | ||
|
||
return RedirectToPage(); | ||
} | ||
catch (Exception ex) | ||
catch (ArgumentException ex) | ||
{ | ||
// SECURITY ISSUE: Exposing exception details in logs without sanitization | ||
_logger.LogError("Regex processing failed: {Exception}", ex.ToString()); | ||
TempData["RegexError"] = $"Regex processing failed: {ex.Message}"; | ||
// Handle invalid regex pattern or input | ||
_logger.LogError("Regex processing failed due to invalid pattern or input: {Exception}", ex.ToString()); | ||
TempData["RegexError"] = "Regex processing failed due to invalid pattern or input."; | ||
return RedirectToPage(); | ||
} | ||
catch (RegexMatchTimeoutException ex) | ||
{ | ||
// Handle regex timeout | ||
_logger.LogError("Regex processing timed out: {Exception}", ex.ToString()); | ||
TempData["RegexError"] = "Regex processing timed out."; | ||
return RedirectToPage(); | ||
} | ||
} | ||
|
||
public IActionResult OnPostTestLogging(string logMessage) |
_logger.LogInformation("User action: {Message}", logMessage); | ||
|
||
// SECURITY ISSUE: Hardcoded credentials for demo purposes | ||
var connectionString = "Server=localhost;Database=TestDB;User Id=admin;Password=Password123!;"; |
Check warning
Code scanning / CodeQL
Useless assignment to local variable Warning
connectionString
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 25 days ago
To fix the problem, simply remove the assignment to the connectionString
variable on line 60, as it is never used. This will clean up the code and eliminate the useless assignment. No other changes are necessary, as the removal does not affect any other logic or functionality in the method. No new imports, methods, or definitions are required.
@@ -57,7 +57,6 @@ | ||
_logger.LogInformation("User action: {Message}", logMessage); | ||
|
||
// SECURITY ISSUE: Hardcoded credentials for demo purposes | ||
var connectionString = "Server=localhost;Database=TestDB;User Id=admin;Password=Password123!;"; | ||
|
||
// SECURITY ISSUE: Potential SQL injection if this were used in actual queries | ||
var sqlQuery = $"INSERT INTO Logs (Message) VALUES ('{logMessage}')"; |
var connectionString = "Server=localhost;Database=TestDB;User Id=admin;Password=Password123!;"; | ||
|
||
// SECURITY ISSUE: Potential SQL injection if this were used in actual queries | ||
var sqlQuery = $"INSERT INTO Logs (Message) VALUES ('{logMessage}')"; |
Check warning
Code scanning / CodeQL
Useless assignment to local variable Warning
sqlQuery
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 25 days ago
To fix the problem, simply remove the assignment to the local variable sqlQuery
on line 63 in the OnPostTestLogging
method of DevSecOps3.cshtml.cs
. Since the value is never read and the assignment has no side effects, it is safe to delete this line. No additional imports, methods, or definitions are required. Only the single line should be removed, and no other changes are necessary.
@@ -60,7 +60,6 @@ | ||
var connectionString = "Server=localhost;Database=TestDB;User Id=admin;Password=Password123!;"; | ||
|
||
// SECURITY ISSUE: Potential SQL injection if this were used in actual queries | ||
var sqlQuery = $"INSERT INTO Logs (Message) VALUES ('{logMessage}')"; | ||
|
||
// SECURITY ISSUE: Using both JSON libraries unnecessarily (dependency confusion risk) | ||
var jsonData = JsonConvert.SerializeObject(new { message = logMessage, timestamp = DateTime.Now }); |
|
||
// SECURITY ISSUE: Using both JSON libraries unnecessarily (dependency confusion risk) | ||
var jsonData = JsonConvert.SerializeObject(new { message = logMessage, timestamp = DateTime.Now }); | ||
var systemJsonData = System.Text.Json.JsonSerializer.Serialize(new { message = logMessage, timestamp = DateTime.Now }); |
Check warning
Code scanning / CodeQL
Useless assignment to local variable Warning
systemJsonData
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 25 days ago
To fix the problem, simply remove the assignment to the unused local variable systemJsonData
on line 67. This means deleting the line:
var systemJsonData = System.Text.Json.JsonSerializer.Serialize(new { message = logMessage, timestamp = DateTime.Now });
No other changes are needed, as the value is not used elsewhere. The rest of the method and class remain unchanged. No imports or additional definitions are required.
@@ -64,7 +64,6 @@ | ||
|
||
// SECURITY ISSUE: Using both JSON libraries unnecessarily (dependency confusion risk) | ||
var jsonData = JsonConvert.SerializeObject(new { message = logMessage, timestamp = DateTime.Now }); | ||
var systemJsonData = System.Text.Json.JsonSerializer.Serialize(new { message = logMessage, timestamp = DateTime.Now }); | ||
|
||
_logger.LogInformation("Serialized data: {JsonData}", jsonData); | ||
|
catch (Exception ex) | ||
{ | ||
// SECURITY ISSUE: Excessive error information disclosure | ||
_logger.LogError("Logging operation failed with full exception: {FullException}", ex); | ||
TempData["LogResult"] = $"Logging failed: {ex.Message} - {ex.StackTrace}"; | ||
return RedirectToPage(); | ||
} |
Check notice
Code scanning / CodeQL
Generic catch clause Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 25 days ago
To fix the problem, replace the generic catch (Exception ex)
clause with more specific exception types that are likely to be thrown in the try
block. For the code in OnPostTestLogging
, the most relevant exceptions are:
ArgumentException
(for invalid arguments to logging or string formatting)JsonException
(for serialization errors fromSystem.Text.Json
)Newtonsoft.Json.JsonException
(for serialization errors from Newtonsoft.Json)SqlException
(if database operations were actually performed, but in this code, the query is only constructed, not executed)
Since the code does not actually execute the SQL query, SqlException
is not needed. The most relevant exceptions are ArgumentException
, JsonException
, and Newtonsoft.Json.JsonException
. You should add multiple catch blocks for these exceptions. For any other unexpected exceptions, you can optionally add a final generic catch block that logs less detailed information, or simply let them propagate.
Required changes:
- Replace the generic catch block with multiple specific catch blocks for the exceptions mentioned above.
- Add necessary using directives if not already present (e.g., for
System.Text.Json
andNewtonsoft.Json
exceptions). - Ensure that the error handling logic remains the same for each specific exception.
-
Copy modified line R75 -
Copy modified lines R77-R78 -
Copy modified lines R81-R92
@@ -72,13 +72,24 @@ | ||
|
||
return RedirectToPage(); | ||
} | ||
catch (Exception ex) | ||
catch (ArgumentException ex) | ||
{ | ||
// SECURITY ISSUE: Excessive error information disclosure | ||
_logger.LogError("Logging operation failed with full exception: {FullException}", ex); | ||
TempData["LogResult"] = $"Logging failed: {ex.Message} - {ex.StackTrace}"; | ||
_logger.LogError("Logging operation failed due to invalid argument: {Exception}", ex); | ||
TempData["LogResult"] = $"Logging failed: {ex.Message}"; | ||
return RedirectToPage(); | ||
} | ||
catch (System.Text.Json.JsonException ex) | ||
{ | ||
_logger.LogError("Logging operation failed during System.Text.Json serialization: {Exception}", ex); | ||
TempData["LogResult"] = $"Logging failed: {ex.Message}"; | ||
return RedirectToPage(); | ||
} | ||
catch (Newtonsoft.Json.JsonException ex) | ||
{ | ||
_logger.LogError("Logging operation failed during Newtonsoft.Json serialization: {Exception}", ex); | ||
TempData["LogResult"] = $"Logging failed: {ex.Message}"; | ||
return RedirectToPage(); | ||
} | ||
} | ||
|
||
// SECURITY ISSUE: Method with potential for misuse if exposed |
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.
Pull Request Overview
This PR implements a new DevSecOps v3 demo page to showcase GitHub Advanced Security (GHAS) features. The implementation includes intentionally vulnerable code patterns designed for security demonstration and training purposes.
- Adds a comprehensive DevSecOps3 page with interactive security demonstrations
- Introduces intentionally insecure code patterns including ReDoS vulnerabilities, log forging, hardcoded credentials, and SQL injection risks
- Updates package dependencies to specific versions for demo compatibility
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 10 comments.
Show a summary per file
File | Description |
---|---|
webapp01.csproj | Downgrades Newtonsoft.Json from 13.0.1 to 12.0.2 for demo requirements |
_Layout.cshtml | Adds navigation link to new DevSecOps v3 page |
Index.cshtml | Adds promotional link to DevSecOps v3 demo page |
DevSecOps3.cshtml.cs | Implements backend model with intentionally vulnerable security patterns for GHAS demonstration |
DevSecOps3.cshtml | Creates comprehensive frontend with interactive security demos and GHAS feature documentation |
@@ -13,7 +13,7 @@ | |||
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.0.2" /> | |||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" /> | |||
<PackageReference Include="System.Text.Json" Version="8.0.4" /> | |||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> | |||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> |
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.
Downgrading Newtonsoft.Json from 13.0.1 to 12.0.2 introduces known security vulnerabilities. Version 12.0.2 has documented CVEs that were fixed in later versions. Consider using the latest secure version unless this downgrade is specifically required for the security demonstration.
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> | |
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> |
Copilot uses AI. Check for mistakes.
|
||
_logger.LogInformation("Testing regex with input: {Input}", userInput); | ||
|
||
var regex = new Regex(vulnerablePattern); |
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.
This regex pattern is vulnerable to ReDoS (Regular Expression Denial of Service) attacks. The nested quantifiers (a+)+ create catastrophic backtracking with malicious inputs, potentially causing application timeouts or crashes.
var regex = new Regex(vulnerablePattern); | |
// FIX: Use a safe regex pattern without nested quantifiers | |
var safePattern = @"^a+$"; | |
_logger.LogInformation("Testing regex with input: {Input}", userInput); | |
var regex = new Regex(safePattern); |
Copilot uses AI. Check for mistakes.
// SECURITY ISSUE: Log forging vulnerability - user input directly written to logs | ||
// Malicious input like "Normal log\r\n[ADMIN] Unauthorized access granted" | ||
// could inject fake log entries | ||
_logger.LogInformation("User action: {Message}", logMessage); |
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.
This logging implementation is vulnerable to log forging attacks. User input is directly logged without sanitization, allowing attackers to inject fake log entries by including newline characters and control sequences.
_logger.LogInformation("User action: {Message}", logMessage); | |
var sanitizedLogMessage = SanitizeForLog(logMessage); | |
_logger.LogInformation("User action: {Message}", sanitizedLogMessage); |
Copilot uses AI. Check for mistakes.
_logger.LogInformation("User action: {Message}", logMessage); | ||
|
||
// SECURITY ISSUE: Hardcoded credentials for demo purposes | ||
var connectionString = "Server=localhost;Database=TestDB;User Id=admin;Password=Password123!;"; |
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.
Hardcoded database credentials pose a serious security risk. Credentials should be stored in secure configuration, environment variables, or a secrets management system, never in source code.
var connectionString = "Server=localhost;Database=TestDB;User Id=admin;Password=Password123!;"; | |
// FIX: Load connection string from environment variable instead of hardcoding | |
var connectionString = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING"); |
Copilot uses AI. Check for mistakes.
var connectionString = "Server=localhost;Database=TestDB;User Id=admin;Password=Password123!;"; | ||
|
||
// SECURITY ISSUE: Potential SQL injection if this were used in actual queries | ||
var sqlQuery = $"INSERT INTO Logs (Message) VALUES ('{logMessage}')"; |
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.
This string concatenation creates a SQL injection vulnerability. User input is directly embedded in the SQL query without parameterization, allowing attackers to execute arbitrary SQL commands.
var sqlQuery = $"INSERT INTO Logs (Message) VALUES ('{logMessage}')"; | |
// FIXED: Use parameterized query to prevent SQL injection | |
var sqlQuery = "INSERT INTO Logs (Message) VALUES (@Message)"; | |
using (var command = new SqlCommand(sqlQuery)) | |
{ | |
command.Parameters.AddWithValue("@Message", logMessage ?? string.Empty); | |
// Note: In this demo, the command is not executed. | |
} |
Copilot uses AI. Check for mistakes.
{ | ||
// SECURITY ISSUE: Excessive error information disclosure | ||
_logger.LogError("Logging operation failed with full exception: {FullException}", ex); | ||
TempData["LogResult"] = $"Logging failed: {ex.Message} - {ex.StackTrace}"; |
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.
Exposing full exception details including stack traces to users can reveal sensitive information about the application structure, file paths, and internal implementation details that could aid attackers.
TempData["LogResult"] = $"Logging failed: {ex.Message} - {ex.StackTrace}"; | |
TempData["LogResult"] = "Logging failed due to an internal error. Please contact support if the problem persists."; |
Copilot uses AI. Check for mistakes.
_logger.LogInformation("Processing sensitive data: {SensitiveData}", processedData); | ||
|
||
// SECURITY ISSUE: Hardcoded secret key | ||
var secretKey = "MySecretKey123!@#"; |
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.
Hardcoded secret keys in source code create serious security vulnerabilities. Secret keys should be stored in secure configuration systems, environment variables, or key management services.
var secretKey = "MySecretKey123!@#"; | |
// Retrieve secret key from environment variable for security | |
var secretKey = Environment.GetEnvironmentVariable("MY_SECRET_KEY"); |
Copilot uses AI. Check for mistakes.
var processedData = userData.ToUpper(); | ||
|
||
// SECURITY ISSUE: Logging sensitive data without redaction | ||
_logger.LogInformation("Processing sensitive data: {SensitiveData}", processedData); |
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.
Logging sensitive data without redaction or masking creates a security risk. Sensitive information should be masked, hashed, or excluded from logs to prevent data exposure through log files.
_logger.LogInformation("Processing sensitive data: {SensitiveData}", processedData); | |
// Mask sensitive data before logging | |
var maskedData = MaskSensitiveData(processedData); | |
_logger.LogInformation("Processing sensitive data: {SensitiveData}", maskedData); |
Copilot uses AI. Check for mistakes.
var encodedData = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(processedData + secretKey)); | ||
|
||
_logger.LogInformation("Encoded result: {EncodedData}", encodedData); | ||
} |
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.
Base64 encoding is not encryption and provides no security. This creates a false sense of security while exposing sensitive data. Use proper cryptographic functions with secure algorithms for data protection.
} | |
// _logger.LogInformation("Processing sensitive data: {SensitiveData}", processedData); // Avoid logging sensitive data in plaintext | |
// SECURITY ISSUE: Hardcoded secret key (for demo only; use secure key management in production) | |
var key = System.Text.Encoding.UTF8.GetBytes("0123456789ABCDEF0123456789ABCDEF"); // 32 bytes for AES-256 | |
var iv = System.Text.Encoding.UTF8.GetBytes("ABCDEF0123456789"); // 16 bytes for AES | |
// Use AES encryption instead of Base64 encoding | |
var encryptedData = EncryptStringToBytes_Aes(processedData, key, iv); | |
var encodedData = Convert.ToBase64String(encryptedData); | |
_logger.LogInformation("Encrypted result (Base64): {EncodedData}", encodedData); | |
} | |
// Helper method for AES encryption | |
private static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV) | |
{ | |
if (plainText == null || plainText.Length <= 0) | |
throw new ArgumentNullException(nameof(plainText)); | |
if (Key == null || Key.Length <= 0) | |
throw new ArgumentNullException(nameof(Key)); | |
if (IV == null || IV.Length <= 0) | |
throw new ArgumentNullException(nameof(IV)); | |
using (Aes aesAlg = Aes.Create()) | |
{ | |
aesAlg.Key = Key; | |
aesAlg.IV = IV; | |
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); | |
using (var msEncrypt = new System.IO.MemoryStream()) | |
{ | |
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) | |
using (var swEncrypt = new System.IO.StreamWriter(csEncrypt)) | |
{ | |
swEncrypt.Write(plainText); | |
} | |
return msEncrypt.ToArray(); | |
} | |
} | |
} |
Copilot uses AI. Check for mistakes.
// SECURITY ISSUE: Potential SQL injection if this were used in actual queries | ||
var sqlQuery = $"INSERT INTO Logs (Message) VALUES ('{logMessage}')"; | ||
|
||
// SECURITY ISSUE: Using both JSON libraries unnecessarily (dependency confusion risk) |
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.
Using both Newtonsoft.Json and System.Text.Json libraries for the same functionality violates the DRY principle and creates unnecessary dependencies. Choose one JSON library and use it consistently throughout the application.
Copilot uses AI. Check for mistakes.
Addresses issue #84