Token导航 LogoToken导航TokenDH.com
研究检索需要联网github未标认证来源可访问clear审计未展示

security安全

Agent Skill

用于辅助安全审计、权限检查、凭据风险、认证流程和常见漏洞排查。它适合让 Agent 梳理敏感配置、检查依赖风险、分析鉴权逻辑或生成安全复核清单。使用时不能把工具输出直接当最终结论,涉及密钥、令牌、用户数据或生产系统时,应先确认最小权限、脱敏方式和操作边界。

总安装

306

周安装

13

GitHub Stars

公开资料未说明

下载量

107
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:security(安全)
来源仓库:https://github.com/yosrbennagra/3sc
仓库路径:skills/security
安装命令:
npx skills add yosrbennagra/3sc --skill "security"
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

AgentSkills.tonpx skills
npx skills add yosrbennagra/3sc --skill "security"

简介

security 用于辅助安全审计、权限检查、凭据风险、认证流程和常见漏洞排查,适合梳理敏感配置、检查依赖风险或生成安全复核清单。

  • 适用于安全审计相关的权限检查、凭据风险分析和漏洞排查,不能将工具输出直接作为最终结论。
  • 通过 npx skills add yosrbennagra/3sc --skill "security" 命令安装。
  • 安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。
  • security 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

name
security
description
Security patterns for the 3SC widget host. Covers credential storage, input validation, secure coding practices, and protecting user data.

Security

Overview

Security is critical for a desktop application that handles user data and loads external plugins. This skill covers security patterns for protecting credentials, validating input, and secure coding practices.

Definition of Done (DoD)

  • [ ] Credentials stored using DPAPI (Windows Data Protection)
  • [ ] User input validated before use
  • [ ] Sensitive data never logged
  • [ ] File paths validated to prevent traversal attacks
  • [ ] Error messages don't expose internal details
  • [ ] Security-sensitive operations are audited

Credential Storage

Windows Data Protection API (DPAPI)

public class SecureStorageService : ISecureStorage
{
    private readonly string _storePath;
    
    public SecureStorageService()
    {
        _storePath = Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
            "3SC", "secure");
        Directory.CreateDirectory(_storePath);
    }
    
    public void Store(string key, string value)
    {
        ArgumentException.ThrowIfNullOrEmpty(key);
        
        var plainBytes = Encoding.UTF8.GetBytes(value);
        var protectedBytes = ProtectedData.Protect(
            plainBytes, 
            entropy: null,  // Add entropy for additional security
            scope: DataProtectionScope.CurrentUser);
        
        var filePath = GetFilePath(key);
        File.WriteAllBytes(filePath, protectedBytes);
        
        Log.Debug("Credential stored: {Key}", key);  // Never log the value!
    }
    
    public string? Retrieve(string key)
    {
        var filePath = GetFilePath(key);
        
        if (!File.Exists(filePath))
            return null;
        
        try
        {
            var protectedBytes = File.ReadAllBytes(filePath);
            var plainBytes = ProtectedData.Unprotect(
                protectedBytes,
                entropy: null,
                scope: DataProtectionScope.CurrentUser);
            
            return Encoding.UTF8.GetString(plainBytes);
        }
        catch (CryptographicException ex)
        {
            Log.Warning(ex, "Failed to decrypt credential: {Key}", key);
            return null;
        }
    }
    
    public void Delete(string key)
    {
        var filePath = GetFilePath(key);
        
        if (File.Exists(filePath))
        {
            // Overwrite before delete for security
            File.WriteAllBytes(filePath, new byte[64]);
            File.Delete(filePath);
        }
    }
    
    private string GetFilePath(string key)
    {
        // Sanitize key to prevent path traversal
        var safeKey = Path.GetFileName(key);
        return Path.Combine(_storePath, $"{safeKey}.dat");
    }
}

Credential Manager for API Keys

public class CredentialManagerService : ICredentialManager
{
    private const string CredentialPrefix = "3SC:";
    
    public void SaveCredential(string target, string username, string password)
    {
        var credential = new Credential
        {
            Target = CredentialPrefix + target,
            Username = username,
            Password = password,
            Type = CredentialType.Generic,
            Persist = PersistType.LocalMachine
        };
        
        credential.Save();
        Log.Information("Credential saved for target: {Target}", target);
    }
    
    public (string? Username, string? Password) GetCredential(string target)
    {
        var credential = new Credential { Target = CredentialPrefix + target };
        
        if (credential.Load())
        {
            return (credential.Username, credential.Password);
        }
        
        return (null, null);
    }
    
    public void DeleteCredential(string target)
    {
        var credential = new Credential { Target = CredentialPrefix + target };
        credential.Delete();
    }
}

Input Validation

Path Validation

public static class PathValidator
{
    private static readonly char[] InvalidChars = Path.GetInvalidPathChars()
        .Concat(new[] { '*', '?', '"', '<', '>', '|' })
        .ToArray();
    
    /// <summary>
    /// Validates and normalizes a file path to prevent traversal attacks.
    /// </summary>
    public static string ValidatePath(string basePath, string relativePath)
    {
        ArgumentException.ThrowIfNullOrEmpty(basePath);
        ArgumentException.ThrowIfNullOrEmpty(relativePath);
        
        // Check for invalid characters
        if (relativePath.IndexOfAny(InvalidChars) >= 0)
        {
            throw new ArgumentException("Path contains invalid characters", nameof(relativePath));
        }
        
        // Normalize and get full path
        var fullPath = Path.GetFullPath(Path.Combine(basePath, relativePath));
        var normalizedBase = Path.GetFullPath(basePath);
        
        // Ensure the path is within the base directory
        if (!fullPath.StartsWith(normalizedBase, StringComparison.OrdinalIgnoreCase))
        {
            throw new SecurityException($"Path traversal attempt detected: {relativePath}");
        }
        
        return fullPath;
    }
    
    /// <summary>
    /// Validates a widget package entry point path.
    /// </summary>
    public static bool IsValidEntryPoint(string widgetPath, string entry)
    {
        if (string.IsNullOrEmpty(entry))
            return false;
        
        // Entry must be a simple filename, no paths
        if (entry != Path.GetFileName(entry))
            return false;
        
        // Must be a DLL
        if (!entry.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
            return false;
        
        // File must exist within widget directory
        var fullPath = Path.Combine(widgetPath, entry);
        return File.Exists(fullPath);
    }
}

String Validation

public static class InputValidator
{
    private static readonly Regex SafeNamePattern = new(
        @"^[a-zA-Z0-9][a-zA-Z0-9\-_.]{0,63}$",
        RegexOptions.Compiled);
    
    public static bool IsValidWidgetKey(string? key)
    {
        return !string.IsNullOrEmpty(key) 
            && key.Length <= 64 
            && SafeNamePattern.IsMatch(key);
    }
    
    public static bool IsValidDisplayName(string? name)
    {
        return !string.IsNullOrWhiteSpace(name) 
            && name.Length <= 128
            && !name.Contains('<')  // Prevent XSS
            && !name.Contains('>');
    }
    
    public static string SanitizeHtml(string input)
    {
        if (string.IsNullOrEmpty(input))
            return string.Empty;
        
        return WebUtility.HtmlEncode(input);
    }
    
    public static string? TruncateWithEllipsis(string? input, int maxLength)
    {
        if (string.IsNullOrEmpty(input) || input.Length <= maxLength)
            return input;
        
        return input[..(maxLength - 3)] + "...";
    }
}

Error Message Security

Safe Error Messages

public static class SafeErrors
{
    // Public-facing error messages (user-visible)
    public const string GenericError = "An unexpected error occurred. Please try again.";
    public const string NetworkError = "Unable to connect. Please check your internet connection.";
    public const string DatabaseError = "Failed to save changes. Please try again.";
    public const string WidgetLoadError = "Failed to load widget. It may be corrupted or incompatible.";
    public const string AuthenticationError = "Authentication failed. Please check your credentials.";
    
    // Never expose these to users:
    // - Stack traces
    // - File paths
    // - Database connection strings
    // - Internal exception messages
    // - Server names or IPs
    
    public static string ToUserMessage(Exception ex)
    {
        return ex switch
        {
            HttpRequestException => NetworkError,
            Microsoft.Data.Sqlite.SqliteException => DatabaseError,
            FileNotFoundException => "The requested file was not found.",
            UnauthorizedAccessException => "Access denied. You may not have permission for this operation.",
            OperationCanceledException => "Operation was cancelled.",
            _ => GenericError
        };
    }
}

// Usage in ViewModel
catch (Exception ex)
{
    Log.Error(ex, "Detailed error for debugging");  // Full details to logs
    ErrorMessage = SafeErrors.ToUserMessage(ex);     // Safe message to UI
}

Audit Logging

Security Events

public static class SecurityAudit
{
    public static void LogCredentialAccess(string target, bool success)
    {
        Log.Information(
            "Security: Credential access - Target: {Target}, Success: {Success}",
            target, success);
    }
    
    public static void LogWidgetLoad(string widgetKey, string path, bool success)
    {
        Log.Information(
            "Security: Widget load - Key: {WidgetKey}, Path: {Path}, Success: {Success}",
            widgetKey, LogSanitizer.MaskPath(path), success);
    }
    
    public static void LogPermissionRequest(string widgetKey, string[] permissions, bool granted)
    {
        Log.Information(
            "Security: Permission request - Widget: {WidgetKey}, Permissions: {@Permissions}, Granted: {Granted}",
            widgetKey, permissions, granted);
    }
    
    public static void LogSuspiciousActivity(string activity, string details)
    {
        Log.Warning(
            "Security: Suspicious activity - Activity: {Activity}, Details: {Details}",
            activity, details);
    }
}

Secure Coding Practices

Memory Security

// Use SecureString for sensitive data in memory (when possible)
public class SecureCredential : IDisposable
{
    private SecureString? _password;
    
    public void SetPassword(string password)
    {
        _password?.Dispose();
        _password = new SecureString();
        
        foreach (var c in password)
        {
            _password.AppendChar(c);
        }
        
        _password.MakeReadOnly();
    }
    
    public string GetPassword()
    {
        if (_password == null)
            return string.Empty;
        
        var ptr = Marshal.SecureStringToBSTR(_password);
        try
        {
            return Marshal.PtrToStringBSTR(ptr);
        }
        finally
        {
            Marshal.ZeroFreeBSTR(ptr);
        }
    }
    
    public void Dispose()
    {
        _password?.Dispose();
        _password = null;
    }
}

Principle of Least Privilege

// Widget permissions model
public class WidgetPermissions
{
    public bool CanAccessNetwork { get; init; }
    public bool CanAccessFileSystem { get; init; }
    public bool CanAccessClipboard { get; init; }
    public bool CanStartProcess { get; init; }
    
    public static WidgetPermissions Default => new()
    {
        CanAccessNetwork = false,
        CanAccessFileSystem = false,
        CanAccessClipboard = false,
        CanStartProcess = false
    };
    
    public static WidgetPermissions FromManifest(string[] permissions)
    {
        return new WidgetPermissions
        {
            CanAccessNetwork = permissions.Contains("network"),
            CanAccessFileSystem = permissions.Contains("filesystem"),
            CanAccessClipboard = permissions.Contains("clipboard"),
            CanStartProcess = permissions.Contains("process")
        };
    }
}

Security Checklist

Before Release

  • [ ] All credentials use DPAPI storage
  • [ ] No hardcoded secrets in code
  • [ ] Error messages sanitized for users
  • [ ] File paths validated
  • [ ] Input validated at boundaries
  • [ ] Audit logging for security events
  • [ ] Widget permissions enforced
  • [ ] No sensitive data in logs

Code Review Security Questions

  1. Does this code handle user input? Is it validated?
  2. Does this code load external data? Is it sanitized?
  3. Does this code access credentials? Is access logged?
  4. Does this error message expose internal details?
  5. Does this file operation validate paths?
  6. Does this widget operation check permissions?

Common Vulnerabilities to Avoid

VulnerabilityPrevention
Path traversalValidate and normalize all paths
Credential exposureUse DPAPI, never log credentials
Information disclosureSanitize error messages
Arbitrary code executionSandbox widgets, validate assemblies
InjectionParameterize all queries
XSS in WebViewSanitize HTML content

References

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Gemini CLI

28.85%
按下载量换算31

windsurf

22.35%
按下载量换算24

trae

18.96%
按下载量换算20

OpenCode

15.07%
按下载量换算16

Codex

8.04%
按下载量换算9

Claude Code

4.06%
按下载量换算4

安全审计

暂无安全审计结果可展示。

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills