Adjusted alert window design and implemented drag & drop security checks

This commit is contained in:
hart_s3 2026-07-20 15:36:39 +02:00
parent 827fff101c
commit 49c0acbdd1
6 changed files with 103 additions and 34 deletions

View File

@ -2404,6 +2404,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::ATTACHDOCUMENTS::T1875575968"] = "Click h
-- Drag and drop files into the marked area or click here to attach documents:
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::ATTACHDOCUMENTS::T230755331"] = "Drag and drop files into the marked area or click here to attach documents:"
-- The file '{0}' could not be checked for prompt injection and was not attached.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::ATTACHDOCUMENTS::T2404630365"] = "The file '{0}' could not be checked for prompt injection and was not attached."
-- Select files to attach
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::ATTACHDOCUMENTS::T2495931372"] = "Select files to attach"
@ -4741,15 +4744,15 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINGGUIDELINEDIALOG::T4250996615"] = "P
-- Chat attachment
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T1071345316"] = "Chat attachment"
-- Danger detected
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T1081126836"] = "Danger detected"
-- Content source
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T1129278507"] = "Content source"
-- Attempt to override instructions
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T161976090"] = "Attempt to override instructions"
-- Security warning
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T1862129203"] = "Security warning"
-- Attempt to expose protected data
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T2050274293"] = "Attempt to expose protected data"
@ -4786,12 +4789,18 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T3448155331"] =
-- Attempt to manipulate an agent
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T355252317"] = "Attempt to manipulate an agent"
-- AI Studio has reliably detected and blocked the suspicious content. Your applications and data remain protected. Please review the content you uploaded.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T3661810823"] = "AI Studio has reliably detected and blocked the suspicious content. Your applications and data remain protected. Please review the content you uploaded."
-- File content
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T3788064862"] = "File content"
-- Persistent or delayed instruction
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T4169123215"] = "Persistent or delayed instruction"
-- Security active
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T4212328947"] = "Security active"
-- Typical attacks on AI systems (e.g. prompt injection) hide instructions within untrusted content to trick an AI model into ignoring its intended rules or performing unintended actions.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T4221674400"] = "Typical attacks on AI systems (e.g. prompt injection) hide instructions within untrusted content to trick an AI model into ignoring its intended rules or performing unintended actions."
@ -6454,12 +6463,12 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2936083926"] = "AI Studio could
-- Writer
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2979224202"] = "Writer"
-- Prompt Injection Detected
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T3580322580"] = "Prompt Injection Detected"
-- Show details
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T3692372066"] = "Show details"
-- Security notice
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T4004397997"] = "Security notice"
-- Information
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T4256323669"] = "Information"

View File

@ -2,6 +2,7 @@ using AIStudio.Chat;
using AIStudio.Dialogs;
using AIStudio.Tools.PluginSystem;
using AIStudio.Tools.Rust;
using AIStudio.Tools.Security;
using AIStudio.Tools.Services;
using AIStudio.Tools.Validation;
@ -75,6 +76,9 @@ public partial class AttachDocuments : MSGComponentBase
[Inject]
private PandocAvailabilityService PandocAvailabilityService { get; init; } = null!;
[Inject]
private PromptInjectionGuardService PromptInjectionGuardService { get; init; } = null!;
private const Placement TOOLBAR_TOOLTIP_PLACEMENT = Placement.Top;
private static readonly string DROP_FILES_HERE_TEXT = TB("Drop files here to attach them.");
@ -184,12 +188,7 @@ public partial class AttachDocuments : MSGComponentBase
}
foreach (var path in paths)
{
if(!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(FileExtensionValidation.UseCase.ATTACHING_CONTENT, path, this.ValidateMediaFileTypes, this.Provider))
continue;
this.DocumentPaths.Add(FileAttachment.FromPath(path));
}
await this.TryAddFileAsync(path);
await this.DocumentPathsChanged.InvokeAsync(this.DocumentPaths);
await this.OnChange(this.DocumentPaths);
@ -232,16 +231,43 @@ public partial class AttachDocuments : MSGComponentBase
if (!File.Exists(selectedFilePath))
continue;
if (!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(FileExtensionValidation.UseCase.ATTACHING_CONTENT, selectedFilePath, this.ValidateMediaFileTypes, this.Provider))
continue;
this.DocumentPaths.Add(FileAttachment.FromPath(selectedFilePath));
await this.TryAddFileAsync(selectedFilePath);
}
await this.DocumentPathsChanged.InvokeAsync(this.DocumentPaths);
await this.OnChange(this.DocumentPaths);
}
private async Task<bool> TryAddFileAsync(string filePath)
{
if (!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(FileExtensionValidation.UseCase.ATTACHING_CONTENT, filePath, this.ValidateMediaFileTypes, this.Provider))
return false;
var attachment = FileAttachment.FromPath(filePath);
if (attachment.Type is FileAttachmentType.DOCUMENT && this.PromptInjectionGuardService.IsProtectionEnabled)
{
try
{
var fileContent = await this.RustService.ReadArbitraryFileData(filePath, int.MaxValue);
await this.PromptInjectionGuardService.EnsureSafeForLlmAsync(fileContent, PromptInjectionSource.ChatAttachment(filePath));
}
catch (PromptInjectionBlockedException)
{
return false;
}
catch (Exception exception)
{
this.Logger.LogError(exception, "File attachment '{FilePath}' could not be checked for prompt injection and will not be attached.", filePath);
await this.MessageBus.SendError(new(
Icons.Material.Filled.Cancel,
string.Format(T("The file '{0}' could not be checked for prompt injection and was not attached."), attachment.FileName)));
return false;
}
}
return this.DocumentPaths.Add(attachment);
}
private async Task OpenAttachmentsDialog()
{
if (this.Disabled)

View File

@ -17,7 +17,7 @@
<MudStack Spacing="0">
<MudText Typo="Typo.h5">
@T("Danger detected")
@T("Security warning")
</MudText>
<MudText Typo="Typo.body2"
@ -26,6 +26,35 @@
</MudText>
</MudStack>
</MudStack>
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Class="mt-4">
<Content>
<MudText Typo="Typo.body2">
@T("Typical attacks on AI systems (e.g. prompt injection) hide instructions within untrusted content to trick an AI model into ignoring its intended rules or performing unintended actions.")
</MudText>
</Content>
</MudAlert>
</MudPaper>
<MudPaper Class="pa-6 mb-4" Elevation="0" Style="background:#f0fff0;border:1px solid #90ee90;">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="3">
<MudAvatar Size="Size.Large"
Color="Color.Success"
Variant="Variant.Filled">
<MudIcon Icon="@Icons.Material.Filled.Check"/>
</MudAvatar>
<MudStack Spacing="0">
<MudText Typo="Typo.h5">
@T("Security active")
</MudText>
<MudText Typo="Typo.body2"
Color="Color.Success">
@T("AI Studio has reliably detected and blocked the suspicious content. Your applications and data remain protected. Please review the content you uploaded.")
</MudText>
</MudStack>
</MudStack>
</MudPaper>
<MudDivider />
@ -41,12 +70,6 @@
</MudStack>
<MudCollapse Expanded="@showPromptInjectionInformation">
<MudText Typo="Typo.body2" Class="mb-4">
<strong>
@T("Typical attacks on AI systems (e.g. prompt injection) hide instructions within untrusted content to trick an AI model into ignoring its intended rules or performing unintended actions.")
</strong>
</MudText>
<MudPaper Outlined="true"
Class="pa-4 mb-4">
<MudGrid>

View File

@ -351,7 +351,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, ILan
};
var dialogReference = await this.DialogService.ShowAsync<PromptInjectionAlertDialog>(
T("Prompt Injection Detected"),
T("Security notice"),
dialogParameters,
DialogOptions.BLOCKING_FULLSCREEN);

View File

@ -2406,6 +2406,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::ATTACHDOCUMENTS::T1875575968"] = "Klicken
-- Drag and drop files into the marked area or click here to attach documents:
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::ATTACHDOCUMENTS::T230755331"] = "Ziehen Sie Dateien in den markierten Bereich oder klicken Sie hier, um Dokumente anzuhängen:"
-- The file '{0}' could not be checked for prompt injection and was not attached.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::ATTACHDOCUMENTS::T2404630365"] = "Die Datei '{0}' konnte nicht auf Prompt-Injection überprüft werden und wurde nicht angehängt."
-- Select files to attach
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::ATTACHDOCUMENTS::T2495931372"] = "Dateien zum Anhängen auswählen"
@ -4743,18 +4746,15 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINGGUIDELINEDIALOG::T4250996615"] = "P
-- Chat attachment
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T1071345316"] = "Dateianhang"
-- Danger detected
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T1081126836"] = "Gefahr erkannt"
-- Content source
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T1129278507"] = "Datei"
-- Prompt injection hides instructions in untrusted content to make an AI model ignore its intended rules or perform unintended actions.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T4221674400"] = "Typische Angriffe auf KI-Systeme (z.B. Prompt Injection) verbergen Anweisungen in nicht vertrauenswürdigen Inhalten, um ein KI-Modell dazu zu bringen, seine vorgesehenen Regeln zu ignorieren oder ungewollte Aktionen auszuführen."
-- Attempt to override instructions
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T161976090"] = "Versuch, Anweisungen zu überschreiben"
-- Security warning
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T1862129203"] = "Sicherheitswarnung"
-- Attempt to expose protected data
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T2050274293"] = "Versuch, geschützte Daten offenzulegen"
@ -4791,12 +4791,21 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T3448155331"] =
-- Attempt to manipulate an agent
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T355252317"] = "Versuch, einen Agenten zu manipulieren"
-- AI Studio has reliably detected and blocked the suspicious content. Your applications and data remain protected. Please review the content you uploaded.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T3661810823"] = "AI Studio hat den verdächtigen Inhalt zuverlässig erkannt und blockiert. Ihre Anwendungen und Daten bleiben geschützt. Bitte überprüfen Sie den von Ihnen hochgeladenen Inhalt."
-- File content
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T3788064862"] = "Inhalt der Datei"
-- Persistent or delayed instruction
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T4169123215"] = "Dauerhafte oder verzögerte Anweisung"
-- Security active
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T4212328947"] = "Sicherheit aktiv"
-- Typical attacks on AI systems
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T4221674400"] = "Typische Angriffe auf KI-Systeme (z.B. Prompt Injection) verbergen Anweisungen in nicht vertrauenswürdigen Inhalten, um ein KI-Modell dazu zu bringen, seine vorgesehenen Regeln zu ignorieren oder ungewollte Aktionen auszuführen."
-- Detected content
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::PROMPTINJECTIONALERTDIALOG::T4223810750"] = "Erkannter Inhalt"
@ -6456,12 +6465,12 @@ UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2936083926"] = "AI Studio konnte
-- Writing
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T2979224202"] = "Schreiben"
-- Prompt Injection Detected
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T3580322580"] = "Prompt-Injection erkannt"
-- Show details
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T3692372066"] = "Details anzeigen"
-- Security notice
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T4004397997"] = "Sicherheitshinweis"
-- Information
UI_TEXT_CONTENT["AISTUDIO::LAYOUT::MAINLAYOUT::T4256323669"] = "Information"

View File

@ -12,9 +12,11 @@ public sealed class PromptInjectionGuardService(
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(PromptInjectionGuardService).Namespace, nameof(PromptInjectionGuardService));
public bool IsProtectionEnabled => settingsManager.ConfigurationData.Chat.EnablePromptInjectionProtection;
public async Task<string> EnsureSafeForLlmAsync(string text, PromptInjectionSource source)
{
if (!settingsManager.ConfigurationData.Chat.EnablePromptInjectionProtection || string.IsNullOrWhiteSpace(text))
if (!this.IsProtectionEnabled || string.IsNullOrWhiteSpace(text))
return text;
var result = scanner.Scan(text, source);