mirror of
https://github.com/securego/gosec.git
synced 2026-01-15 09:53:40 +08:00
Compare commits
2 Commits
b6eea26df8
...
v2.22.11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
424fc4cd9c | ||
|
|
aa2e2fb1bd |
45
README.md
45
README.md
@@ -256,17 +256,52 @@ gosec -exclude-generated ./...
|
||||
```
|
||||
|
||||
### Auto fixing vulnerabilities
|
||||
|
||||
gosec can suggest fixes based on AI recommendation. It will call an AI API to receive a suggestion for a security finding.
|
||||
|
||||
You can enable this feature by providing the following command line arguments:
|
||||
- `ai-api-provider`: the name of the AI API provider, currently only `gemini`is supported.
|
||||
- `ai-api-key` or set the environment variable `GOSEC_AI_API_KEY`: the key to access the AI API,
|
||||
For gemini, you can create an API key following [these instructions](https://ai.google.dev/gemini-api/docs/api-key).
|
||||
- `ai-endpoint`: the endpoint of the AI provider, this is optional argument.
|
||||
|
||||
- `ai-api-provider`: the name of the AI API provider. Supported providers:
|
||||
- **Gemini**: `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-2.5-flash-lite`, `gemini-2.0-flash`, `gemini-2.0-flash-lite` (default)
|
||||
- **Claude**: `claude-sonnet-4-0` (default), `claude-opus-4-0`, `claude-opus-4-1`, `claude-sonnet-3-7`
|
||||
- **OpenAI**: `gpt-4o` (default), `gpt-4o-mini`
|
||||
- **Custom OpenAI-compatible**: Any custom model name (requires `ai-base-url`)
|
||||
- `ai-api-key` or set the environment variable `GOSEC_AI_API_KEY`: the key to access the AI API
|
||||
- For Gemini, you can create an API key following [these instructions](https://ai.google.dev/gemini-api/docs/api-key)
|
||||
- For Claude, get your API key from [Anthropic Console](https://console.anthropic.com/)
|
||||
- For OpenAI, get your API key from [OpenAI Platform](https://platform.openai.com/api-keys)
|
||||
- `ai-base-url`: (optional) custom base URL for OpenAI-compatible APIs (e.g., Azure OpenAI, LocalAI, Ollama)
|
||||
- `ai-skip-ssl`: (optional) skip SSL certificate verification for AI API (useful for self-signed certificates)
|
||||
|
||||
**Examples:**
|
||||
|
||||
```bash
|
||||
gosec -ai-api-provider="gemini" -ai-api-key="your_key" ./...
|
||||
# Using Gemini
|
||||
gosec -ai-api-provider="gemini-2.0-flash" -ai-api-key="your_key" ./...
|
||||
|
||||
# Using Claude
|
||||
gosec -ai-api-provider="claude-sonnet-4-0" -ai-api-key="your_key" ./...
|
||||
|
||||
# Using OpenAI
|
||||
gosec -ai-api-provider="gpt-4o" -ai-api-key="your_key" ./...
|
||||
|
||||
# Using Azure OpenAI
|
||||
gosec -ai-api-provider="gpt-4o" \
|
||||
-ai-api-key="your_azure_key" \
|
||||
-ai-base-url="https://your-resource.openai.azure.com/openai/deployments/your-deployment" \
|
||||
./...
|
||||
|
||||
# Using local Ollama with custom model
|
||||
gosec -ai-api-provider="llama3.2" \
|
||||
-ai-base-url="http://localhost:11434/v1" \
|
||||
./...
|
||||
|
||||
# Using self-signed certificate API
|
||||
gosec -ai-api-provider="custom-model" \
|
||||
-ai-api-key="your_key" \
|
||||
-ai-base-url="https://internal-api.company.com/v1" \
|
||||
-ai-skip-ssl \
|
||||
./...
|
||||
```
|
||||
|
||||
### Annotating code
|
||||
|
||||
@@ -13,7 +13,8 @@ import (
|
||||
const (
|
||||
AIProviderFlagHelp = `AI API provider to generate auto fixes to issues. Valid options are:
|
||||
- gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite, gemini-2.0-flash, gemini-2.0-flash-lite (gemini, default);
|
||||
- claude-sonnet-4-0 (claude, default), claude-sonnet-4-5, claude-opus-4-0, claude-opus-4-1, claude-haiku-4-5, claude-sonnet-3-7`
|
||||
- claude-sonnet-4-0 (claude, default), claude-sonnet-4-5, claude-opus-4-0, claude-opus-4-1, claude-haiku-4-5, claude-sonnet-3-7
|
||||
- gpt-4o (openai, default), gpt-4o-mini`
|
||||
|
||||
AIPrompt = `Provide a brief explanation and a solution to fix this security issue
|
||||
in Go programming language: %q.
|
||||
@@ -27,7 +28,7 @@ type GenAIClient interface {
|
||||
}
|
||||
|
||||
// GenerateSolution generates a solution for the given issues using the specified AI provider
|
||||
func GenerateSolution(model, aiAPIKey string, issues []*issue.Issue) (err error) {
|
||||
func GenerateSolution(model, aiAPIKey, baseURL string, skipSSL bool, issues []*issue.Issue) (err error) {
|
||||
var client GenAIClient
|
||||
|
||||
switch {
|
||||
@@ -35,13 +36,27 @@ func GenerateSolution(model, aiAPIKey string, issues []*issue.Issue) (err error)
|
||||
client, err = NewClaudeClient(model, aiAPIKey)
|
||||
case strings.HasPrefix(model, "gemini"):
|
||||
client, err = NewGeminiClient(model, aiAPIKey)
|
||||
case strings.HasPrefix(model, "gpt"):
|
||||
config := OpenAIConfig{
|
||||
Model: model,
|
||||
APIKey: aiAPIKey,
|
||||
BaseURL: baseURL,
|
||||
SkipSSL: skipSSL,
|
||||
}
|
||||
client, err = NewOpenAIClient(config)
|
||||
default:
|
||||
// Default to OpenAI-compatible API for custom models
|
||||
config := OpenAIConfig{
|
||||
Model: model,
|
||||
APIKey: aiAPIKey,
|
||||
BaseURL: baseURL,
|
||||
SkipSSL: skipSSL,
|
||||
}
|
||||
client, err = NewOpenAIClient(config)
|
||||
}
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
if err != nil {
|
||||
return fmt.Errorf("initializing AI client: %w", err)
|
||||
case client == nil:
|
||||
return fmt.Errorf("unsupported AI backend: %s", model)
|
||||
}
|
||||
|
||||
return generateSolution(client, issues)
|
||||
|
||||
@@ -81,8 +81,11 @@ func TestGenerateSolution_UnsupportedProvider(t *testing.T) {
|
||||
}
|
||||
|
||||
// Act
|
||||
err := GenerateSolution("unsupported-provider", "test-api-key", issues)
|
||||
// Note: With default OpenAI-compatible fallback, this will attempt to create an OpenAI client
|
||||
// The test will fail during client initialization due to missing/invalid API key or base URL
|
||||
err := GenerateSolution("custom-model", "", "", false, issues)
|
||||
|
||||
// Assert
|
||||
require.EqualError(t, err, "unsupported AI backend: unsupported-provider")
|
||||
// Expect an error during client initialization or API call
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
120
autofix/openai.go
Normal file
120
autofix/openai.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package autofix
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/openai/openai-go/v3"
|
||||
"github.com/openai/openai-go/v3/option"
|
||||
)
|
||||
|
||||
const (
|
||||
ModelGPT4o = openai.ChatModelGPT4o
|
||||
ModelGPT4oMini = openai.ChatModelGPT4oMini
|
||||
DefaultOpenAIBaseURL = "https://api.openai.com/v1"
|
||||
)
|
||||
|
||||
var _ GenAIClient = (*openaiWrapper)(nil)
|
||||
|
||||
type OpenAIConfig struct {
|
||||
Model string
|
||||
APIKey string
|
||||
BaseURL string
|
||||
MaxTokens int
|
||||
Temperature float64
|
||||
SkipSSL bool
|
||||
}
|
||||
|
||||
type openaiWrapper struct {
|
||||
client openai.Client
|
||||
model openai.ChatModel
|
||||
maxTokens int
|
||||
temperature float64
|
||||
}
|
||||
|
||||
func NewOpenAIClient(config OpenAIConfig) (GenAIClient, error) {
|
||||
var options []option.RequestOption
|
||||
|
||||
if config.APIKey != "" {
|
||||
options = append(options, option.WithAPIKey(config.APIKey))
|
||||
}
|
||||
|
||||
// Support custom base URL (for OpenAI-compatible APIs)
|
||||
if config.BaseURL != "" {
|
||||
options = append(options, option.WithBaseURL(config.BaseURL))
|
||||
}
|
||||
|
||||
// Support skip SSL verification
|
||||
if config.SkipSSL {
|
||||
// Create custom HTTP client with InsecureSkipVerify
|
||||
httpClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true, // #nosec G402
|
||||
},
|
||||
},
|
||||
}
|
||||
options = append(options, option.WithHTTPClient(httpClient))
|
||||
}
|
||||
|
||||
openaiModel := parseOpenAIModel(config.Model)
|
||||
|
||||
// Set default values
|
||||
maxTokens := config.MaxTokens
|
||||
if maxTokens == 0 {
|
||||
maxTokens = 1024
|
||||
}
|
||||
|
||||
temperature := config.Temperature
|
||||
if temperature == 0 {
|
||||
temperature = 0.7
|
||||
}
|
||||
|
||||
return &openaiWrapper{
|
||||
client: openai.NewClient(options...),
|
||||
model: openaiModel,
|
||||
maxTokens: maxTokens,
|
||||
temperature: temperature,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o *openaiWrapper) GenerateSolution(ctx context.Context, prompt string) (string, error) {
|
||||
params := openai.ChatCompletionNewParams{
|
||||
Model: o.model,
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.UserMessage(prompt),
|
||||
},
|
||||
}
|
||||
|
||||
// Set optional parameters if available
|
||||
// Using WithMaxTokens and WithTemperature methods if they exist in v3
|
||||
resp, err := o.client.Chat.Completions.New(ctx, params)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("generating autofix: %w", err)
|
||||
}
|
||||
|
||||
if resp == nil || len(resp.Choices) == 0 {
|
||||
return "", errors.New("no autofix returned by openai")
|
||||
}
|
||||
|
||||
content := resp.Choices[0].Message.Content
|
||||
if content == "" {
|
||||
return "", errors.New("nothing found in the first autofix returned by openai")
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
|
||||
func parseOpenAIModel(model string) openai.ChatModel {
|
||||
switch model {
|
||||
case "gpt-4o":
|
||||
return openai.ChatModelGPT4o
|
||||
case "gpt-4o-mini":
|
||||
return openai.ChatModelGPT4oMini
|
||||
default:
|
||||
return model
|
||||
}
|
||||
}
|
||||
@@ -159,6 +159,12 @@ var (
|
||||
// key to implementing AI provider services
|
||||
flagAiAPIKey = flag.String("ai-api-key", "", "Key to access the AI API")
|
||||
|
||||
// base URL for AI API (optional, for OpenAI-compatible APIs)
|
||||
flagAiBaseURL = flag.String("ai-base-url", "", "Base URL for AI API (e.g., for OpenAI-compatible services)")
|
||||
|
||||
// skip SSL verification for AI API
|
||||
flagAiSkipSSL = flag.Bool("ai-skip-ssl", false, "Skip SSL certificate verification for AI API")
|
||||
|
||||
// exclude the folders from scan
|
||||
flagDirsExclude arrayFlags
|
||||
|
||||
@@ -501,7 +507,7 @@ func main() {
|
||||
aiEnabled := *flagAiAPIProvider != ""
|
||||
|
||||
if len(issues) > 0 && aiEnabled {
|
||||
err := autofix.GenerateSolution(*flagAiAPIProvider, aiAPIKey, issues)
|
||||
err := autofix.GenerateSolution(*flagAiAPIProvider, aiAPIKey, *flagAiBaseURL, *flagAiSkipSSL, issues)
|
||||
if err != nil {
|
||||
logger.Print(err)
|
||||
}
|
||||
|
||||
1
go.mod
1
go.mod
@@ -9,6 +9,7 @@ require (
|
||||
github.com/mozilla/tls-observatory v0.0.0-20250923143331-eef96233227e
|
||||
github.com/onsi/ginkgo/v2 v2.27.2
|
||||
github.com/onsi/gomega v1.38.2
|
||||
github.com/openai/openai-go/v3 v3.8.1
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
|
||||
github.com/stretchr/testify v1.11.1
|
||||
go.yaml.in/yaml/v3 v3.0.4
|
||||
|
||||
2
go.sum
2
go.sum
@@ -311,6 +311,8 @@ github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zw
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
|
||||
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
|
||||
github.com/openai/openai-go/v3 v3.8.1 h1:b+YWsmwqXnbpSHWQEntZAkKciBZ5CJXwL68j+l59UDg=
|
||||
github.com/openai/openai-go/v3 v3.8.1/go.mod h1:UOpNxkqC9OdNXNUfpNByKOtB4jAL0EssQXq5p8gO0Xs=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
|
||||
@@ -67,6 +67,7 @@ var ruleToCWE = map[string]string{
|
||||
"G112": "400",
|
||||
"G114": "676",
|
||||
"G115": "190",
|
||||
"G116": "838",
|
||||
"G201": "89",
|
||||
"G202": "89",
|
||||
"G203": "79",
|
||||
|
||||
@@ -76,6 +76,7 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList {
|
||||
{"G111", "Detect http.Dir('/') as a potential risk", NewDirectoryTraversal},
|
||||
{"G112", "Detect ReadHeaderTimeout not configured as a potential risk", NewSlowloris},
|
||||
{"G114", "Use of net/http serve function that has no support for setting timeouts", NewHTTPServeWithoutTimeouts},
|
||||
{"G116", "Detect Trojan Source attacks using bidirectional Unicode characters", NewTrojanSource},
|
||||
|
||||
// injection
|
||||
{"G201", "SQL query construction using format string", NewSQLStrFormat},
|
||||
|
||||
@@ -107,6 +107,10 @@ var _ = Describe("gosec rules", func() {
|
||||
runner("G114", testutils.SampleCodeG114)
|
||||
})
|
||||
|
||||
It("should detect Trojan Source attacks using bidirectional Unicode characters", func() {
|
||||
runner("G116", testutils.SampleCodeG116)
|
||||
})
|
||||
|
||||
It("should detect sql injection via format strings", func() {
|
||||
runner("G201", testutils.SampleCodeG201)
|
||||
})
|
||||
|
||||
96
rules/trojansource.go
Normal file
96
rules/trojansource.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"os"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type trojanSource struct {
|
||||
issue.MetaData
|
||||
bidiChars map[rune]struct{}
|
||||
}
|
||||
|
||||
func (r *trojanSource) ID() string {
|
||||
return r.MetaData.ID
|
||||
}
|
||||
|
||||
func (r *trojanSource) Match(node ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||
if file, ok := node.(*ast.File); ok {
|
||||
fobj := c.FileSet.File(file.Pos())
|
||||
if fobj == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
content, err := os.ReadFile(fobj.Name())
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for _, ch := range string(content) {
|
||||
if _, exists := r.bidiChars[ch]; exists {
|
||||
return c.NewIssue(node, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// func (r *trojanSource) Match(node ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||
// if file, ok := node.(*ast.File); ok {
|
||||
// fobj := c.FileSet.File(file.Pos())
|
||||
// if fobj == nil {
|
||||
// return nil, nil
|
||||
// }
|
||||
|
||||
// file, err := os.Open(fobj.Name())
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
|
||||
// defer file.Close()
|
||||
|
||||
// scanner := bufio.NewScanner(file)
|
||||
// for scanner.Scan() {
|
||||
// line := scanner.Text()
|
||||
// for _, ch := range line {
|
||||
// if _, exists := r.bidiChars[ch]; exists {
|
||||
// return c.NewIssue(node, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if err := scanner.Err(); err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// return nil, nil
|
||||
// }
|
||||
|
||||
func NewTrojanSource(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
return &trojanSource{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: issue.High,
|
||||
Confidence: issue.Medium,
|
||||
What: "Potential Trojan Source vulnerability via use of bidirectional text control characters",
|
||||
},
|
||||
bidiChars: map[rune]struct{}{
|
||||
'\u202a': {},
|
||||
'\u202b': {},
|
||||
'\u202c': {},
|
||||
'\u202d': {},
|
||||
'\u202e': {},
|
||||
'\u2066': {},
|
||||
'\u2067': {},
|
||||
'\u2068': {},
|
||||
'\u2069': {},
|
||||
'\u200e': {},
|
||||
'\u200f': {},
|
||||
},
|
||||
}, []ast.Node{(*ast.File)(nil)}
|
||||
}
|
||||
83
testutils/g116_samples.go
Normal file
83
testutils/g116_samples.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package testutils
|
||||
|
||||
import "github.com/securego/gosec/v2"
|
||||
|
||||
// #nosec - This file intentionally contains bidirectional Unicode characters
|
||||
// for testing trojan source detection. The G116 rule scans the entire file content (not just AST nodes)
|
||||
// because trojan source attacks work by manipulating visual representation of code through bidirectional
|
||||
// text control characters, which can appear in comments, strings or anywhere in the source file.
|
||||
// Without this #nosec exclusion, gosec would detect these test samples as actual vulnerabilities.
|
||||
var (
|
||||
// SampleCodeG116 - TrojanSource code snippets
|
||||
SampleCodeG116 = []CodeSample{
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// This comment contains bidirectional unicode: access\u202e\u2066 granted\u2069\u202d\n\tisAdmin := false\n\tfmt.Println(\"Access status:\", isAdmin)\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Trojan source with RLO character\n\taccessLevel := \"user\"\n\t// Actually assigns \"nimda\" due to bidi chars: accessLevel = \"\u202enimda\"\n\tif accessLevel == \"admin\" {\n\t\tfmt.Println(\"Access granted\")\n\t}\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// String with bidirectional override\n\tusername := \"admin\u202e \u2066Check if admin\u2069 \u2066\"\n\tpassword := \"secret\"\n\tfmt.Println(username, password)\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Contains LRI (Left-to-Right Isolate) U+2066\n\tcomment := \"Safe comment \u2066with hidden text\u2069\"\n\tfmt.Println(comment)\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Contains RLI (Right-to-Left Isolate) U+2067\n\tmessage := \"Normal text \u2067hidden\u2069\"\n\tfmt.Println(message)\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Contains FSI (First Strong Isolate) U+2068\n\ttext := \"Text with \u2068hidden content\u2069\"\n\tfmt.Println(text)\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Contains LRE (Left-to-Right Embedding) U+202A\n\tembedded := \"Text with \u202aembedded\u202c content\"\n\tfmt.Println(embedded)\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Contains RLE (Right-to-Left Embedding) U+202B\n\trtlEmbedded := \"Text with \u202bembedded\u202c content\"\n\tfmt.Println(rtlEmbedded)\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Contains PDF (Pop Directional Formatting) U+202C\n\tformatted := \"Text with \u202cformatting\"\n\tfmt.Println(formatted)\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Contains LRO (Left-to-Right Override) U+202D\n\toverride := \"Text \u202doverride\"\n\tfmt.Println(override)\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Contains RLO (Right-to-Left Override) U+202E\n\trloText := \"Text \u202eoverride\"\n\tfmt.Println(rloText)\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Contains RLM (Right-to-Left Mark) U+200F\n\tmarked := \"Text \u200fmarked\"\n\tfmt.Println(marked)\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{"\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Contains LRM (Left-to-Right Mark) U+200E\n\tlrmText := \"Text \u200emarked\"\n\tfmt.Println(lrmText)\n}\n"}, 1, gosec.NewConfig()},
|
||||
{[]string{`
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Safe code without bidirectional characters
|
||||
func main() {
|
||||
username := "admin"
|
||||
password := "secret"
|
||||
fmt.Println("Username:", username)
|
||||
fmt.Println("Password:", password)
|
||||
}
|
||||
`}, 0, gosec.NewConfig()},
|
||||
{[]string{`
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Normal comment with regular text
|
||||
func main() {
|
||||
// This is a safe comment
|
||||
isAdmin := true
|
||||
if isAdmin {
|
||||
fmt.Println("Access granted")
|
||||
}
|
||||
}
|
||||
`}, 0, gosec.NewConfig()},
|
||||
{[]string{`
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
// Regular ASCII characters only
|
||||
message := "Hello, World!"
|
||||
fmt.Println(message)
|
||||
}
|
||||
`}, 0, gosec.NewConfig()},
|
||||
{[]string{`
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func authenticateUser(username, password string) bool {
|
||||
// Normal authentication logic
|
||||
if username == "admin" && password == "secret" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func main() {
|
||||
result := authenticateUser("user", "pass")
|
||||
fmt.Println("Authenticated:", result)
|
||||
}
|
||||
`}, 0, gosec.NewConfig()},
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user