Skip to content

Genres and tags#165

Merged
Sirush merged 5 commits intoproductionfrom
master
Nov 27, 2025
Merged

Genres and tags#165
Sirush merged 5 commits intoproductionfrom
master

Conversation

@Sirush
Copy link
Copy Markdown
Owner

@Sirush Sirush commented Nov 27, 2025

No description provided.

@github-advanced-security
Copy link
Copy Markdown
Contributor

This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation.

.ToListAsync();

logger.LogInformation("Admin retrieved genre mappings: Count={Count}, Provider={Provider}, JitenGenre={JitenGenre}, Search={Search}",
mappings.Count, provider, jitenGenre, search);

Check warning

Code scanning / CodeQL

Log entries created from user input Medium

This log entry depends on a
user-provided value
.

Copilot Autofix

AI 5 months ago

The best way to fix this problem is to sanitize the search user input before it is logged. Specifically, the sanitization should remove any line breaks (e.g., \n, \r) from the string and potentially trim whitespace. Since we're operating in a plaintext logging context, this avoids attack via control characters to forge new log entries.

To implement the fix:

  • Within the GetGenreMappings method (Jiten.Api/Controllers/AdminController.Genres.cs), ensure that the value passed for search in the logger is sanitized.
  • Before logging, create a sanitized version of search by removing line breaks using string.Replace for both \r and \n, or via a helper if desired.
  • Pass the sanitized value to LogInformation (on line 39).
  • No changes are needed elsewhere in the code, and no dependencies are needed.
    If there are other similar logs that use user input, same fix should be applied to each, but for this case, only line 39 needs change.

Suggested changeset 1
Jiten.Api/Controllers/AdminController.Genres.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/Jiten.Api/Controllers/AdminController.Genres.cs b/Jiten.Api/Controllers/AdminController.Genres.cs
--- a/Jiten.Api/Controllers/AdminController.Genres.cs
+++ b/Jiten.Api/Controllers/AdminController.Genres.cs
@@ -35,8 +35,10 @@
                                           })
                              .ToListAsync();
 
+        // Sanitize 'search' to prevent log forging by removing newlines
+        var sanitizedSearch = search?.Replace("\r", "").Replace("\n", "");
         logger.LogInformation("Admin retrieved genre mappings: Count={Count}, Provider={Provider}, JitenGenre={JitenGenre}, Search={Search}",
-                              mappings.Count, provider, jitenGenre, search);
+                              mappings.Count, provider, jitenGenre, sanitizedSearch);
 
         return Ok(mappings);
     }
EOF
@@ -35,8 +35,10 @@
})
.ToListAsync();

// Sanitize 'search' to prevent log forging by removing newlines
var sanitizedSearch = search?.Replace("\r", "").Replace("\n", "");
logger.LogInformation("Admin retrieved genre mappings: Count={Count}, Provider={Provider}, JitenGenre={JitenGenre}, Search={Search}",
mappings.Count, provider, jitenGenre, search);
mappings.Count, provider, jitenGenre, sanitizedSearch);

return Ok(mappings);
}
Copilot is powered by AI and may make mistakes. Always verify output.
await dbContext.SaveChangesAsync();

logger.LogInformation("Admin created genre mapping: MappingId={MappingId}, Provider={Provider}, ExternalName={ExternalName}, JitenGenre={JitenGenre}",
mapping.ExternalGenreMappingId, mapping.Provider, mapping.ExternalGenreName, mapping.JitenGenre);

Check warning

Code scanning / CodeQL

Log entries created from user input Medium

This log entry depends on a
user-provided value
.

Copilot Autofix

AI 5 months ago

To fix this problem, sanitize user input before including it in log entries. For text log files, removing line breaks and other control characters from external user values prevents delimiter injection and log entry forging. The best, least disruptive fix is to ensure mapping.ExternalGenreName is sanitized before being logged:

  • On line 68, update the log call to use a sanitized version of mapping.ExternalGenreName.
  • This can be done inline by calling .Replace("\r", "").Replace("\n", "") on the value, or by defining a helper method (if needed) to sanitize log input, but for a single case, inline works.
  • Only lines related to logging mapping.ExternalGenreName are affected; elsewhere, user input is not logged, or the log does not contain unsanitized user-content.
  • No external dependencies are required; use built-in string operations.
Suggested changeset 1
Jiten.Api/Controllers/AdminController.Genres.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/Jiten.Api/Controllers/AdminController.Genres.cs b/Jiten.Api/Controllers/AdminController.Genres.cs
--- a/Jiten.Api/Controllers/AdminController.Genres.cs
+++ b/Jiten.Api/Controllers/AdminController.Genres.cs
@@ -65,7 +65,7 @@
         await dbContext.SaveChangesAsync();
 
         logger.LogInformation("Admin created genre mapping: MappingId={MappingId}, Provider={Provider}, ExternalName={ExternalName}, JitenGenre={JitenGenre}",
-                              mapping.ExternalGenreMappingId, mapping.Provider, mapping.ExternalGenreName, mapping.JitenGenre);
+                              mapping.ExternalGenreMappingId, mapping.Provider, mapping.ExternalGenreName.Replace("\r", "").Replace("\n", ""), mapping.JitenGenre);
 
         return Ok(new { Message = "Genre mapping created successfully", Id = mapping.ExternalGenreMappingId });
     }
EOF
@@ -65,7 +65,7 @@
await dbContext.SaveChangesAsync();

logger.LogInformation("Admin created genre mapping: MappingId={MappingId}, Provider={Provider}, ExternalName={ExternalName}, JitenGenre={JitenGenre}",
mapping.ExternalGenreMappingId, mapping.Provider, mapping.ExternalGenreName, mapping.JitenGenre);
mapping.ExternalGenreMappingId, mapping.Provider, mapping.ExternalGenreName.Replace("\r", "").Replace("\n", ""), mapping.JitenGenre);

return Ok(new { Message = "Genre mapping created successfully", Id = mapping.ExternalGenreMappingId });
}
Copilot is powered by AI and may make mistakes. Always verify output.
await dbContext.SaveChangesAsync();

logger.LogInformation("Admin created tag mapping: MappingId={MappingId}, Provider={Provider}, ExternalName={ExternalName}, TagId={TagId}",
mapping.ExternalTagMappingId, mapping.Provider, mapping.ExternalTagName, mapping.TagId);

Check warning

Code scanning / CodeQL

Log entries created from user input Medium

This log entry depends on a
user-provided value
.

Copilot Autofix

AI 5 months ago

To fix the problem, we should sanitize mapping.ExternalTagName before it is included in any log entry. This specifically means removing potentially dangerous characters, such as newline (\n, \r) and other control characters which can be used to inject new log entries. The best approach is to use string.Replace (or Regex) to remove these characters.

Only line 70 requires modification: before passing mapping.ExternalTagName to the logger, sanitize it by removing CR/LF. This can be done inline using
.Replace("\r", "").Replace("\n", "").

No new dependencies or external methods are necessary to implement this fix—use C# built-in string functions. No changes should be made to existing functionality except the sanitization for this log entry.


Suggested changeset 1
Jiten.Api/Controllers/AdminController.Tags.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/Jiten.Api/Controllers/AdminController.Tags.cs b/Jiten.Api/Controllers/AdminController.Tags.cs
--- a/Jiten.Api/Controllers/AdminController.Tags.cs
+++ b/Jiten.Api/Controllers/AdminController.Tags.cs
@@ -67,7 +67,7 @@
         await dbContext.SaveChangesAsync();
 
         logger.LogInformation("Admin created tag mapping: MappingId={MappingId}, Provider={Provider}, ExternalName={ExternalName}, TagId={TagId}",
-                              mapping.ExternalTagMappingId, mapping.Provider, mapping.ExternalTagName, mapping.TagId);
+                              mapping.ExternalTagMappingId, mapping.Provider, mapping.ExternalTagName.Replace("\r", "").Replace("\n", ""), mapping.TagId);
 
         return Ok(new { Message = "Tag mapping created successfully", Id = mapping.ExternalTagMappingId });
     }
EOF
@@ -67,7 +67,7 @@
await dbContext.SaveChangesAsync();

logger.LogInformation("Admin created tag mapping: MappingId={MappingId}, Provider={Provider}, ExternalName={ExternalName}, TagId={TagId}",
mapping.ExternalTagMappingId, mapping.Provider, mapping.ExternalTagName, mapping.TagId);
mapping.ExternalTagMappingId, mapping.Provider, mapping.ExternalTagName.Replace("\r", "").Replace("\n", ""), mapping.TagId);

return Ok(new { Message = "Tag mapping created successfully", Id = mapping.ExternalTagMappingId });
}
Copilot is powered by AI and may make mistakes. Always verify output.
dbContext.Tags.Add(tag);
await dbContext.SaveChangesAsync();

logger.LogInformation("Admin created tag: TagId={TagId}, Name={Name}", tag.TagId, tag.Name);

Check warning

Code scanning / CodeQL

Log entries created from user input Medium

This log entry depends on a
user-provided value
.

logger.LogInformation("Admin added new deck: Title={Title}, MediaType={MediaType}, SubdeckCount={SubdeckCount}",
model.OriginalTitle, model.MediaType, metadata.Children?.Count ?? 0);
model.OriginalTitle, model.MediaType, metadata.Children?.Count ?? 0);

Check warning

Code scanning / CodeQL

Log entries created from user input Medium

This log entry depends on a
user-provided value
.

Copilot Autofix

AI 5 months ago

To fix the issue, we must sanitize user-provided input before logging it, ensuring it cannot affect or forge new log entries. For plain-text logs, the recommended approach is to remove (or encode) all newline sequences (\r, \n, and combinations), which could be achieved by replacing them in the string before logging:

  • Update the call to logger.LogInformation on line 170 to use a sanitized version of model.OriginalTitle where all newline sequences (\r, \n) are removed.
  • Define the sanitized value immediately before the log statement for clarity.
  • No new methods are strictly necessary, but you can use string.Replace or a regular expression to remove all line breaks.
  • If you're already using System.Text.RegularExpressions, you can use it to remove all control characters if desired; otherwise, at minimum, replace \r and \n with an empty string.

All changes are contained within the method in Jiten.Api/Controllers/AdminController.cs.


Suggested changeset 1
Jiten.Api/Controllers/AdminController.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/Jiten.Api/Controllers/AdminController.cs b/Jiten.Api/Controllers/AdminController.cs
--- a/Jiten.Api/Controllers/AdminController.cs
+++ b/Jiten.Api/Controllers/AdminController.cs
@@ -166,8 +166,10 @@
 
             backgroundJobs.Enqueue<ParseJob>(job => job.Parse(metadata, model.MediaType, bool.Parse(config["StoreRawText"] ?? "false")));
 
+            // Sanitize user-provided title to prevent log forging
+            var sanitizedTitle = model.OriginalTitle?.Replace("\r", "").Replace("\n", "");
             logger.LogInformation("Admin added new deck: Title={Title}, MediaType={MediaType}, SubdeckCount={SubdeckCount}",
-                                  model.OriginalTitle, model.MediaType, metadata.Children?.Count ?? 0);
+                                  sanitizedTitle, model.MediaType, metadata.Children?.Count ?? 0);
 
             return Ok(new
                       {
EOF
@@ -166,8 +166,10 @@

backgroundJobs.Enqueue<ParseJob>(job => job.Parse(metadata, model.MediaType, bool.Parse(config["StoreRawText"] ?? "false")));

// Sanitize user-provided title to prevent log forging
var sanitizedTitle = model.OriginalTitle?.Replace("\r", "").Replace("\n", "");
logger.LogInformation("Admin added new deck: Title={Title}, MediaType={MediaType}, SubdeckCount={SubdeckCount}",
model.OriginalTitle, model.MediaType, metadata.Children?.Count ?? 0);
sanitizedTitle, model.MediaType, metadata.Children?.Count ?? 0);

return Ok(new
{
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
{
logger.LogInformation("User reported deck issue: DeckId={DeckId}, IssueType={IssueType}",
request.DeckId, request.IssueType);
request.DeckId, request.IssueType);

Check warning

Code scanning / CodeQL

Log entries created from user input Medium

This log entry depends on a
user-provided value
.

Copilot Autofix

AI 5 months ago

To fix this issue, sanitize the user input before logging it. Specifically, for log entries that might be written as plain text, remove or replace newline characters in user-provided data before passing them to the logger. In MediaDeckController.cs, this means sanitizing request.IssueType before passing it to the logger (lines 1523 and 1528). The fix involves introducing a utility method that strips or replaces newlines from user input, and using this method on request.IssueType wherever it is logged. The best placement for the helper is inside the existing method as a private helper, similar to SanitizeForDiscord.

Edits:

  • Add a helper function (e.g., SanitizeForLog(string s)) inside the ReportIssue method to replace or strip newlines.
  • Sanitize request.IssueType (and, optionally, any other potentially controllable strings, but the alert specifically cites IssueType) before passing to the logger on lines 1523 and 1528.
  • No change to Discord-side sanitization.

Suggested changeset 1
Jiten.Api/Controllers/MediaDeckController.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/Jiten.Api/Controllers/MediaDeckController.cs b/Jiten.Api/Controllers/MediaDeckController.cs
--- a/Jiten.Api/Controllers/MediaDeckController.cs
+++ b/Jiten.Api/Controllers/MediaDeckController.cs
@@ -1519,15 +1519,26 @@
 
         if (result.IsSuccessStatusCode)
         {
+            // Sanitize IssueType for logging to prevent log forging/newline injection
+            var safeLogIssueType = SanitizeForLog(request.IssueType);
             logger.LogInformation("User reported deck issue: DeckId={DeckId}, IssueType={IssueType}",
-                                  request.DeckId, request.IssueType);
+                                  request.DeckId, safeLogIssueType);
             return Ok();
         }
 
+        var safeLogIssueTypeFail = SanitizeForLog(request.IssueType);
         logger.LogWarning("Failed to send deck issue report: DeckId={DeckId}, IssueType={IssueType}",
-                          request.DeckId, request.IssueType);
+                          request.DeckId, safeLogIssueTypeFail);
         return BadRequest("Failed to send report");
 
+        // Removes newlines, carriage returns, and trims the value for safe logging.
+        string SanitizeForLog(string input)
+        {
+            return string.IsNullOrEmpty(input)
+                ? string.Empty
+                : input.Replace("\r", "").Replace("\n", "").Trim();
+        }
+
         string SanitizeForDiscord(string input)
         {
             if (string.IsNullOrEmpty(input))
EOF
@@ -1519,15 +1519,26 @@

if (result.IsSuccessStatusCode)
{
// Sanitize IssueType for logging to prevent log forging/newline injection
var safeLogIssueType = SanitizeForLog(request.IssueType);
logger.LogInformation("User reported deck issue: DeckId={DeckId}, IssueType={IssueType}",
request.DeckId, request.IssueType);
request.DeckId, safeLogIssueType);
return Ok();
}

var safeLogIssueTypeFail = SanitizeForLog(request.IssueType);
logger.LogWarning("Failed to send deck issue report: DeckId={DeckId}, IssueType={IssueType}",
request.DeckId, request.IssueType);
request.DeckId, safeLogIssueTypeFail);
return BadRequest("Failed to send report");

// Removes newlines, carriage returns, and trims the value for safe logging.
string SanitizeForLog(string input)
{
return string.IsNullOrEmpty(input)
? string.Empty
: input.Replace("\r", "").Replace("\n", "").Trim();
}

string SanitizeForDiscord(string input)
{
if (string.IsNullOrEmpty(input))
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated

logger.LogWarning("Failed to send deck issue report: DeckId={DeckId}, IssueType={IssueType}",
request.DeckId, request.IssueType);
request.DeckId, request.IssueType);

Check warning

Code scanning / CodeQL

Log entries created from user input Medium

This log entry depends on a
user-provided value
.

Copilot Autofix

AI 5 months ago

To fix this issue, we need to ensure that user input (request.IssueType) does not introduce new lines or other control characters into the log entry. The best fix is to sanitize request.IssueType before logging: specifically, replace or remove any newline (\n, \r) or control characters from the input before passing it to the logger. This can be done by replacing such characters with an empty string using String.Replace or a regular expression. The fix should be minimally invasive: sanitize just before logging in the logger.LogWarning call on line 1528 and in the corresponding LogInformation call on line 1523 for consistency. No new dependencies are needed, as the required functionality is in the standard library.

Suggested changeset 1
Jiten.Api/Controllers/MediaDeckController.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/Jiten.Api/Controllers/MediaDeckController.cs b/Jiten.Api/Controllers/MediaDeckController.cs
--- a/Jiten.Api/Controllers/MediaDeckController.cs
+++ b/Jiten.Api/Controllers/MediaDeckController.cs
@@ -1519,13 +1519,15 @@
 
         if (result.IsSuccessStatusCode)
         {
+            var sanitizedIssueType = request.IssueType.Replace("\r", "").Replace("\n", "");
             logger.LogInformation("User reported deck issue: DeckId={DeckId}, IssueType={IssueType}",
-                                  request.DeckId, request.IssueType);
+                                  request.DeckId, sanitizedIssueType);
             return Ok();
         }
 
+        var sanitizedIssueType = request.IssueType.Replace("\r", "").Replace("\n", "");
         logger.LogWarning("Failed to send deck issue report: DeckId={DeckId}, IssueType={IssueType}",
-                          request.DeckId, request.IssueType);
+                          request.DeckId, sanitizedIssueType);
         return BadRequest("Failed to send report");
 
         string SanitizeForDiscord(string input)
EOF
@@ -1519,13 +1519,15 @@

if (result.IsSuccessStatusCode)
{
var sanitizedIssueType = request.IssueType.Replace("\r", "").Replace("\n", "");
logger.LogInformation("User reported deck issue: DeckId={DeckId}, IssueType={IssueType}",
request.DeckId, request.IssueType);
request.DeckId, sanitizedIssueType);
return Ok();
}

var sanitizedIssueType = request.IssueType.Replace("\r", "").Replace("\n", "");
logger.LogWarning("Failed to send deck issue report: DeckId={DeckId}, IssueType={IssueType}",
request.DeckId, request.IssueType);
request.DeckId, sanitizedIssueType);
return BadRequest("Failed to send report");

string SanitizeForDiscord(string input)
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
@Sirush Sirush merged commit ccf0a30 into production Nov 27, 2025
2 of 3 checks passed
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.

2 participants