diff --git a/pkg/action/diff.go b/pkg/action/diff.go
index eecf0e1e1..b8cca290a 100644
--- a/pkg/action/diff.go
+++ b/pkg/action/diff.go
@@ -8,6 +8,7 @@ import (
"fmt"
"log/slog"
"math"
+ "os"
"path/filepath"
"regexp"
"sync"
@@ -32,7 +33,27 @@ func relFileReport(ctx context.Context, c malcontent.Config, fromPath string) (m
if files.Value.Skipped != "" || files.Value.Error != "" {
continue
}
- rel, err := filepath.Rel(fromPath, files.Value.Path)
+ // Evaluate symlinks to cover edge cases like macOS' /private/tmp -> /tmp symlink
+ // Also, remove any filenames to correctly determine the relative path
+ // Using "." and "." will show as modifications for completely unrelated files and paths
+ info, err := os.Stat(fromPath)
+ if err != nil {
+ return nil, fmt.Errorf("failed to stat file %s: %w", fromPath, err)
+ }
+ dir := filepath.Dir(fromPath)
+ var fromRoot string
+ if info.IsDir() {
+ fromRoot, err = filepath.EvalSymlinks(fromPath)
+ } else {
+ fromRoot, err = filepath.EvalSymlinks(dir)
+ }
+ if err != nil {
+ return nil, fmt.Errorf("failed to evaluate symlink for %s: %w", fromPath, err)
+ }
+ if fromRoot == "." {
+ fromRoot = fromPath
+ }
+ rel, err := filepath.Rel(fromRoot, files.Value.Path)
if err != nil {
return nil, fmt.Errorf("rel(%q,%q): %w", fromPath, files.Value.Path, err)
}
@@ -99,6 +120,52 @@ func processSrc(ctx context.Context, c malcontent.Config, src, dest map[string]*
}
}
+func processDest(ctx context.Context, c malcontent.Config, from, to map[string]*malcontent.FileReport, d *malcontent.DiffReport) {
+ // findings that exist only in the destination
+ for relPath, tr := range to {
+ fr, exists := from[relPath]
+ if !exists {
+ d.Added.Set(relPath, tr)
+ continue
+ }
+
+ fileDestination(ctx, c, fr, tr, relPath, d)
+ }
+}
+
+func fileDestination(ctx context.Context, c malcontent.Config, fr, tr *malcontent.FileReport, relPath string, d *malcontent.DiffReport) {
+ // We've now established that this file exists in both source and destination
+ if fr.RiskScore < c.MinFileRisk && tr.RiskScore < c.MinFileRisk {
+ clog.FromContext(ctx).Info("diff does not meet min trigger level", slog.Any("path", tr.Path))
+ return
+ }
+
+ // Filter files that are marked as added
+ if filterDiff(ctx, c, fr, tr) {
+ return
+ }
+
+ abs := createFileReport(tr, fr)
+
+ // if destination behavior is not in the source
+ for _, tb := range tr.Behaviors {
+ if !behaviorExists(tb, fr.Behaviors) {
+ tb.DiffAdded = true
+ abs.Behaviors = append(abs.Behaviors, tb)
+ continue
+ }
+ }
+
+ // are there already modified behaviors for this file?
+ rel, exists := d.Modified.Get(relPath)
+ if !exists {
+ d.Modified.Set(relPath, abs)
+ } else {
+ rel.Behaviors = append(rel.Behaviors, abs.Behaviors...)
+ d.Modified.Set(relPath, rel)
+ }
+}
+
func handleFile(ctx context.Context, c malcontent.Config, fr, tr *malcontent.FileReport, relPath string, d *malcontent.DiffReport) {
// We've now established that file exists in both source & destination
if fr.RiskScore < c.MinFileRisk && tr.RiskScore < c.MinFileRisk {
@@ -148,52 +215,6 @@ func behaviorExists(b *malcontent.Behavior, behaviors []*malcontent.Behavior) bo
return false
}
-func processDest(ctx context.Context, c malcontent.Config, from, to map[string]*malcontent.FileReport, d *malcontent.DiffReport) {
- // findings that exist only in the destination
- for relPath, tr := range to {
- fr, exists := from[relPath]
- if !exists {
- d.Added.Set(relPath, tr)
- continue
- }
-
- fileDestination(ctx, c, fr, tr, relPath, d)
- }
-}
-
-func fileDestination(ctx context.Context, c malcontent.Config, fr, tr *malcontent.FileReport, relPath string, d *malcontent.DiffReport) {
- // We've now established that this file exists in both source and destination
- if fr.RiskScore < c.MinFileRisk && tr.RiskScore < c.MinFileRisk {
- clog.FromContext(ctx).Info("diff does not meet min trigger level", slog.Any("path", tr.Path))
- return
- }
-
- // Filter files that are marked as added
- if filterDiff(ctx, c, fr, tr) {
- return
- }
-
- abs := createFileReport(tr, fr)
-
- // if destination behavior is not in the source
- for _, tb := range tr.Behaviors {
- if !behaviorExists(tb, fr.Behaviors) {
- tb.DiffAdded = true
- abs.Behaviors = append(abs.Behaviors, tb)
- }
- }
-
- // are there already modified behaviors for this file?
- if _, exists := d.Modified.Get(relPath); !exists {
- d.Modified.Set(relPath, abs)
- } else {
- if rel, exists := d.Modified.Get(relPath); exists {
- rel.Behaviors = append(rel.Behaviors, abs.Behaviors...)
- d.Modified.Set(relPath, rel)
- }
- }
-}
-
// filterMap filters orderedmap pairs by checking for matches against a slice of compiled regular expression patterns.
func filterMap(om *orderedmap.OrderedMap[string, *malcontent.FileReport], ps []*regexp.Regexp, c chan<- *orderedmap.Pair[string, *malcontent.FileReport], wg *sync.WaitGroup) {
defer wg.Done()
diff --git a/test_data/linux/2023.FreeDownloadManager/freedownloadmanager.sdiff b/test_data/linux/2023.FreeDownloadManager/freedownloadmanager.sdiff
index a6a60c09e..c5fa915f4 100644
--- a/test_data/linux/2023.FreeDownloadManager/freedownloadmanager.sdiff
+++ b/test_data/linux/2023.FreeDownloadManager/freedownloadmanager.sdiff
@@ -1,19 +1,34 @@
-*** changed: linux/2023.FreeDownloadManager/freedownloadmanager_infected_postinst
+--- missing: freedownloadmanager_clear_postinst
+-data/embedded/pgp_key
+-exec/install_additional/add_apt_key
+-exec/shell/ignore_output
+-fs/path/etc
+-fs/path/usr_bin
+-net/download
+-net/url/embedded
+++++ added: freedownloadmanager_infected_postinst
+3P/threat_hunting/touch
+anti-static/base64/exec
+anti-static/base64/http_agent
+data/base64/external
+data/embedded/base64_terms
+data/embedded/base64_url
++data/embedded/pgp_key
+data/encoding/base64
+evasion/hidden_files/var_tmp
++exec/install_additional/add_apt_key
+exec/shell/exec
++exec/shell/ignore_output
+fs/directory/create
+fs/file/delete_forcibly
+fs/file/make_executable
+fs/file/times_set
++fs/path/etc
+fs/path/tmp
++fs/path/usr_bin
+fs/path/var
+fs/permission/modify
++net/download
++net/url/embedded
+persist/cron/echo_tab
+persist/cron/tab
diff --git a/test_data/linux/2024.sbcl.market/sbcl.sdiff b/test_data/linux/2024.sbcl.market/sbcl.sdiff
index 2f69d0d75..07252357a 100644
--- a/test_data/linux/2024.sbcl.market/sbcl.sdiff
+++ b/test_data/linux/2024.sbcl.market/sbcl.sdiff
@@ -1,4 +1,43 @@
-*** changed: linux/2024.sbcl.market/sbcl.dirty
+--- missing: sbcl.clean
+-data/compression/zstd
+-discover/user/HOME
+-discover/user/USER
+-evasion/hidden_files/var_tmp
+-exec/dylib/address_check
+-exec/dylib/symbol_address
+-exec/program
+-exec/program/background
+-exec/shell/echo
+-fs/file/delete
+-fs/file/truncate
+-fs/link_read
+-fs/path/dev
+-fs/path/tmp
+-fs/path/var
+-fs/permission/modify
+-fs/proc/self_exe
+-fs/symlink_resolve
+-net/url/embedded
+++++ added: sbcl.dirty
+anti-static/packer/high_entropy
++data/compression/zstd
+data/embedded/zstd
++discover/user/HOME
++discover/user/USER
++evasion/hidden_files/var_tmp
++exec/dylib/address_check
++exec/dylib/symbol_address
++exec/program
++exec/program/background
++exec/shell/echo
++fs/file/delete
++fs/file/truncate
++fs/link_read
++fs/path/dev
++fs/path/tmp
++fs/path/var
++fs/permission/modify
++fs/proc/self_exe
++fs/symlink_resolve
+net/dns/txt
++net/url/embedded
diff --git a/test_data/linux/clean/aws-c-io/aws-c-io.sdiff b/test_data/linux/clean/aws-c-io/aws-c-io.sdiff
index aade5d31b..d4ad5f296 100644
--- a/test_data/linux/clean/aws-c-io/aws-c-io.sdiff
+++ b/test_data/linux/clean/aws-c-io/aws-c-io.sdiff
@@ -1 +1 @@
-*** changed: linux/clean/aws-c-io/aws-c-io-0.14.11-r0.spdx.json
+>>> moved: aws-c-io-0.14.10-r0.spdx.json -> linux/clean/aws-c-io/aws-c-io-0.14.11-r0.spdx.json (score: 0.979310)
diff --git a/test_data/macOS/2023.3CX/libffmpeg.change_decrease.mdiff b/test_data/macOS/2023.3CX/libffmpeg.change_decrease.mdiff
index a25b5ba03..25cab4d32 100644
Binary files a/test_data/macOS/2023.3CX/libffmpeg.change_decrease.mdiff and b/test_data/macOS/2023.3CX/libffmpeg.change_decrease.mdiff differ
diff --git a/test_data/macOS/2023.3CX/libffmpeg.change_increase.mdiff b/test_data/macOS/2023.3CX/libffmpeg.change_increase.mdiff
index 87749b643..9cc63d76b 100644
Binary files a/test_data/macOS/2023.3CX/libffmpeg.change_increase.mdiff and b/test_data/macOS/2023.3CX/libffmpeg.change_increase.mdiff differ
diff --git a/test_data/macOS/2023.3CX/libffmpeg.change_unrelated.mdiff b/test_data/macOS/2023.3CX/libffmpeg.change_unrelated.mdiff
index d7de1e6b9..5553b1d69 100644
--- a/test_data/macOS/2023.3CX/libffmpeg.change_unrelated.mdiff
+++ b/test_data/macOS/2023.3CX/libffmpeg.change_unrelated.mdiff
@@ -1,23 +1,23 @@
-## Changed: macOS/clean/ls [🟡 MEDIUM → 🟢 LOW]
+## Deleted: libffmpeg.dylib [🟡 MEDIUM]
-### 2 new behaviors
+| RISK | KEY | DESCRIPTION | EVIDENCE |
+|---------|------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| -MEDIUM | [data/base64/decode](https://github.com/chainguard-dev/malcontent/blob/main/rules/data/base64/base64-decode.yara#py_base64_decode) | decode base64 strings | [base64_decode](https://github.com/search?q=base64_decode&type=code) |
+| -MEDIUM | [fs/path/tmp](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/path/tmp.yara#tmp_path) | path reference within /tmp | [/tmp/%sXXXXXX](https://github.com/search?q=%2Ftmp%2F%25sXXXXXX&type=code) |
+| -MEDIUM | [impact/remote_access/agent](https://github.com/chainguard-dev/malcontent/blob/main/rules/impact/remote_access/agent.yara#agent) | references an 'agent' | [user_agent](https://github.com/search?q=user_agent&type=code) |
+| -MEDIUM | [net/http/post](https://github.com/chainguard-dev/malcontent/blob/main/rules/net/http/post.yara#http_post) | submits content to websites | [HTTP](https://github.com/search?q=HTTP&type=code)
[POST](https://github.com/search?q=POST&type=code)
[http](https://github.com/search?q=http&type=code) |
+| -LOW | [crypto/aes](https://github.com/chainguard-dev/malcontent/blob/main/rules/crypto/aes.yara#crypto_aes) | Supports AES (Advanced Encryption Standard) | [AES](https://github.com/search?q=AES&type=code) |
+| -LOW | [data/encoding/base64](https://github.com/chainguard-dev/malcontent/blob/main/rules/data/encoding/base64.yara#b64) | Supports base64 encoded strings | [base64](https://github.com/search?q=base64&type=code) |
+| -LOW | [exec/shell/TERM](https://github.com/chainguard-dev/malcontent/blob/main/rules/exec/shell/TERM.yara#TERM) | [Look up or override terminal settings](https://www.gnu.org/software/gettext/manual/html_node/The-TERM-variable.html) | [TERM](https://github.com/search?q=TERM&type=code) |
+| -LOW | [fs/directory/create](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/directory/directory-create.yara#mkdir) | [creates directories](https://man7.org/linux/man-pages/man2/mkdir.2.html) | [mkdir](https://github.com/search?q=mkdir&type=code) |
+| -LOW | [net/url/parse](https://github.com/chainguard-dev/malcontent/blob/main/rules/net/url/parse.yara#url_handle) | Handles URL strings | [URLContext](https://github.com/search?q=URLContext&type=code) |
+| -LOW | [process/multithreaded](https://github.com/chainguard-dev/malcontent/blob/main/rules/process/multithreaded.yara#pthread_create) | [creates pthreads](https://man7.org/linux/man-pages/man3/pthread_create.3.html) | [pthread_create](https://github.com/search?q=pthread_create&type=code) |
-| RISK | KEY | DESCRIPTION | EVIDENCE |
-|------|------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| +LOW | **[fs/directory/traverse](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/directory/directory-traverse.yara#fts)** | traverse filesystem hierarchy | [_fts_children](https://github.com/search?q=_fts_children&type=code)
[_fts_close](https://github.com/search?q=_fts_close&type=code)
[_fts_open](https://github.com/search?q=_fts_open&type=code)
[_fts_read](https://github.com/search?q=_fts_read&type=code)
[_fts_set](https://github.com/search?q=_fts_set&type=code) |
-| +LOW | **[fs/link_read](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/link-read.yara#readlink)** | [read value of a symbolic link](https://man7.org/linux/man-pages/man2/readlink.2.html) | [readlink](https://github.com/search?q=readlink&type=code) |
+## Added: ls [🟢 LOW]
-### 9 removed behaviors
-
-| RISK | KEY | DESCRIPTION | EVIDENCE |
-|---------|------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| -MEDIUM | [data/base64/decode](https://github.com/chainguard-dev/malcontent/blob/main/rules/data/base64/base64-decode.yara#py_base64_decode) | decode base64 strings | [base64_decode](https://github.com/search?q=base64_decode&type=code) |
-| -MEDIUM | [fs/path/tmp](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/path/tmp.yara#tmp_path) | path reference within /tmp | [/tmp/%sXXXXXX](https://github.com/search?q=%2Ftmp%2F%25sXXXXXX&type=code) |
-| -MEDIUM | [impact/remote_access/agent](https://github.com/chainguard-dev/malcontent/blob/main/rules/impact/remote_access/agent.yara#agent) | references an 'agent' | [user_agent](https://github.com/search?q=user_agent&type=code) |
-| -MEDIUM | [net/http/post](https://github.com/chainguard-dev/malcontent/blob/main/rules/net/http/post.yara#http_post) | submits content to websites | [HTTP](https://github.com/search?q=HTTP&type=code)
[POST](https://github.com/search?q=POST&type=code)
[http](https://github.com/search?q=http&type=code) |
-| -LOW | [crypto/aes](https://github.com/chainguard-dev/malcontent/blob/main/rules/crypto/aes.yara#crypto_aes) | Supports AES (Advanced Encryption Standard) | [AES](https://github.com/search?q=AES&type=code) |
-| -LOW | [data/encoding/base64](https://github.com/chainguard-dev/malcontent/blob/main/rules/data/encoding/base64.yara#b64) | Supports base64 encoded strings | [base64](https://github.com/search?q=base64&type=code) |
-| -LOW | [fs/directory/create](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/directory/directory-create.yara#mkdir) | [creates directories](https://man7.org/linux/man-pages/man2/mkdir.2.html) | [mkdir](https://github.com/search?q=mkdir&type=code) |
-| -LOW | [net/url/parse](https://github.com/chainguard-dev/malcontent/blob/main/rules/net/url/parse.yara#url_handle) | Handles URL strings | [URLContext](https://github.com/search?q=URLContext&type=code) |
-| -LOW | [process/multithreaded](https://github.com/chainguard-dev/malcontent/blob/main/rules/process/multithreaded.yara#pthread_create) | [creates pthreads](https://man7.org/linux/man-pages/man3/pthread_create.3.html) | [pthread_create](https://github.com/search?q=pthread_create&type=code) |
+| RISK | KEY | DESCRIPTION | EVIDENCE |
+|------|------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| +LOW | **[exec/shell/TERM](https://github.com/chainguard-dev/malcontent/blob/main/rules/exec/shell/TERM.yara#TERM)** | [Look up or override terminal settings](https://www.gnu.org/software/gettext/manual/html_node/The-TERM-variable.html) | [TERM](https://github.com/search?q=TERM&type=code) |
+| +LOW | **[fs/directory/traverse](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/directory/directory-traverse.yara#fts)** | traverse filesystem hierarchy | [_fts_children](https://github.com/search?q=_fts_children&type=code)
[_fts_close](https://github.com/search?q=_fts_close&type=code)
[_fts_open](https://github.com/search?q=_fts_open&type=code)
[_fts_read](https://github.com/search?q=_fts_read&type=code)
[_fts_set](https://github.com/search?q=_fts_set&type=code) |
+| +LOW | **[fs/link_read](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/link-read.yara#readlink)** | [read value of a symbolic link](https://man7.org/linux/man-pages/man2/readlink.2.html) | [readlink](https://github.com/search?q=readlink&type=code) |
diff --git a/test_data/macOS/2023.3CX/libffmpeg.decrease.mdiff b/test_data/macOS/2023.3CX/libffmpeg.decrease.mdiff
index e69de29bb..25cab4d32 100644
Binary files a/test_data/macOS/2023.3CX/libffmpeg.decrease.mdiff and b/test_data/macOS/2023.3CX/libffmpeg.decrease.mdiff differ
diff --git a/test_data/macOS/2023.3CX/libffmpeg.dirty.mdiff b/test_data/macOS/2023.3CX/libffmpeg.dirty.mdiff
index 87749b643..9cc63d76b 100644
Binary files a/test_data/macOS/2023.3CX/libffmpeg.dirty.mdiff and b/test_data/macOS/2023.3CX/libffmpeg.dirty.mdiff differ
diff --git a/test_data/macOS/2023.3CX/libffmpeg.increase.mdiff b/test_data/macOS/2023.3CX/libffmpeg.increase.mdiff
index 87749b643..9cc63d76b 100644
Binary files a/test_data/macOS/2023.3CX/libffmpeg.increase.mdiff and b/test_data/macOS/2023.3CX/libffmpeg.increase.mdiff differ
diff --git a/test_data/macOS/2023.3CX/libffmpeg.increase_unrelated.mdiff b/test_data/macOS/2023.3CX/libffmpeg.increase_unrelated.mdiff
index e88e500e7..7224f0c19 100644
--- a/test_data/macOS/2023.3CX/libffmpeg.increase_unrelated.mdiff
+++ b/test_data/macOS/2023.3CX/libffmpeg.increase_unrelated.mdiff
@@ -1,23 +1,23 @@
-## Changed: macOS/2023.3CX/libffmpeg.dylib [🟢 LOW → 🟡 MEDIUM]
+## Deleted: ls [🟢 LOW]
-### 9 new behaviors
+| RISK | KEY | DESCRIPTION | EVIDENCE |
+|------|--------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| -LOW | [exec/shell/TERM](https://github.com/chainguard-dev/malcontent/blob/main/rules/exec/shell/TERM.yara#TERM) | [Look up or override terminal settings](https://www.gnu.org/software/gettext/manual/html_node/The-TERM-variable.html) | [TERM](https://github.com/search?q=TERM&type=code) |
+| -LOW | [fs/directory/traverse](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/directory/directory-traverse.yara#fts) | traverse filesystem hierarchy | [_fts_children](https://github.com/search?q=_fts_children&type=code)
[_fts_close](https://github.com/search?q=_fts_close&type=code)
[_fts_open](https://github.com/search?q=_fts_open&type=code)
[_fts_read](https://github.com/search?q=_fts_read&type=code)
[_fts_set](https://github.com/search?q=_fts_set&type=code) |
+| -LOW | [fs/link_read](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/link-read.yara#readlink) | [read value of a symbolic link](https://man7.org/linux/man-pages/man2/readlink.2.html) | [readlink](https://github.com/search?q=readlink&type=code) |
-| RISK | KEY | DESCRIPTION | EVIDENCE |
-|---------|----------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| +MEDIUM | **[data/base64/decode](https://github.com/chainguard-dev/malcontent/blob/main/rules/data/base64/base64-decode.yara#py_base64_decode)** | decode base64 strings | [base64_decode](https://github.com/search?q=base64_decode&type=code) |
-| +MEDIUM | **[fs/path/tmp](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/path/tmp.yara#tmp_path)** | path reference within /tmp | [/tmp/%sXXXXXX](https://github.com/search?q=%2Ftmp%2F%25sXXXXXX&type=code) |
-| +MEDIUM | **[impact/remote_access/agent](https://github.com/chainguard-dev/malcontent/blob/main/rules/impact/remote_access/agent.yara#agent)** | references an 'agent' | [user_agent](https://github.com/search?q=user_agent&type=code) |
-| +MEDIUM | **[net/http/post](https://github.com/chainguard-dev/malcontent/blob/main/rules/net/http/post.yara#http_post)** | submits content to websites | [HTTP](https://github.com/search?q=HTTP&type=code)
[POST](https://github.com/search?q=POST&type=code)
[http](https://github.com/search?q=http&type=code) |
-| +LOW | **[crypto/aes](https://github.com/chainguard-dev/malcontent/blob/main/rules/crypto/aes.yara#crypto_aes)** | Supports AES (Advanced Encryption Standard) | [AES](https://github.com/search?q=AES&type=code) |
-| +LOW | **[data/encoding/base64](https://github.com/chainguard-dev/malcontent/blob/main/rules/data/encoding/base64.yara#b64)** | Supports base64 encoded strings | [base64](https://github.com/search?q=base64&type=code) |
-| +LOW | **[fs/directory/create](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/directory/directory-create.yara#mkdir)** | [creates directories](https://man7.org/linux/man-pages/man2/mkdir.2.html) | [mkdir](https://github.com/search?q=mkdir&type=code) |
-| +LOW | **[net/url/parse](https://github.com/chainguard-dev/malcontent/blob/main/rules/net/url/parse.yara#url_handle)** | Handles URL strings | [URLContext](https://github.com/search?q=URLContext&type=code) |
-| +LOW | **[process/multithreaded](https://github.com/chainguard-dev/malcontent/blob/main/rules/process/multithreaded.yara#pthread_create)** | [creates pthreads](https://man7.org/linux/man-pages/man3/pthread_create.3.html) | [pthread_create](https://github.com/search?q=pthread_create&type=code) |
+## Added: libffmpeg.dylib [🟡 MEDIUM]
-### 2 removed behaviors
-
-| RISK | KEY | DESCRIPTION | EVIDENCE |
-|------|--------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| -LOW | [fs/directory/traverse](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/directory/directory-traverse.yara#fts) | traverse filesystem hierarchy | [_fts_children](https://github.com/search?q=_fts_children&type=code)
[_fts_close](https://github.com/search?q=_fts_close&type=code)
[_fts_open](https://github.com/search?q=_fts_open&type=code)
[_fts_read](https://github.com/search?q=_fts_read&type=code)
[_fts_set](https://github.com/search?q=_fts_set&type=code) |
-| -LOW | [fs/link_read](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/link-read.yara#readlink) | [read value of a symbolic link](https://man7.org/linux/man-pages/man2/readlink.2.html) | [readlink](https://github.com/search?q=readlink&type=code) |
+| RISK | KEY | DESCRIPTION | EVIDENCE |
+|---------|----------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| +MEDIUM | **[data/base64/decode](https://github.com/chainguard-dev/malcontent/blob/main/rules/data/base64/base64-decode.yara#py_base64_decode)** | decode base64 strings | [base64_decode](https://github.com/search?q=base64_decode&type=code) |
+| +MEDIUM | **[fs/path/tmp](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/path/tmp.yara#tmp_path)** | path reference within /tmp | [/tmp/%sXXXXXX](https://github.com/search?q=%2Ftmp%2F%25sXXXXXX&type=code) |
+| +MEDIUM | **[impact/remote_access/agent](https://github.com/chainguard-dev/malcontent/blob/main/rules/impact/remote_access/agent.yara#agent)** | references an 'agent' | [user_agent](https://github.com/search?q=user_agent&type=code) |
+| +MEDIUM | **[net/http/post](https://github.com/chainguard-dev/malcontent/blob/main/rules/net/http/post.yara#http_post)** | submits content to websites | [HTTP](https://github.com/search?q=HTTP&type=code)
[POST](https://github.com/search?q=POST&type=code)
[http](https://github.com/search?q=http&type=code) |
+| +LOW | **[crypto/aes](https://github.com/chainguard-dev/malcontent/blob/main/rules/crypto/aes.yara#crypto_aes)** | Supports AES (Advanced Encryption Standard) | [AES](https://github.com/search?q=AES&type=code) |
+| +LOW | **[data/encoding/base64](https://github.com/chainguard-dev/malcontent/blob/main/rules/data/encoding/base64.yara#b64)** | Supports base64 encoded strings | [base64](https://github.com/search?q=base64&type=code) |
+| +LOW | **[exec/shell/TERM](https://github.com/chainguard-dev/malcontent/blob/main/rules/exec/shell/TERM.yara#TERM)** | [Look up or override terminal settings](https://www.gnu.org/software/gettext/manual/html_node/The-TERM-variable.html) | [TERM](https://github.com/search?q=TERM&type=code) |
+| +LOW | **[fs/directory/create](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/directory/directory-create.yara#mkdir)** | [creates directories](https://man7.org/linux/man-pages/man2/mkdir.2.html) | [mkdir](https://github.com/search?q=mkdir&type=code) |
+| +LOW | **[net/url/parse](https://github.com/chainguard-dev/malcontent/blob/main/rules/net/url/parse.yara#url_handle)** | Handles URL strings | [URLContext](https://github.com/search?q=URLContext&type=code) |
+| +LOW | **[process/multithreaded](https://github.com/chainguard-dev/malcontent/blob/main/rules/process/multithreaded.yara#pthread_create)** | [creates pthreads](https://man7.org/linux/man-pages/man3/pthread_create.3.html) | [pthread_create](https://github.com/search?q=pthread_create&type=code) |
diff --git a/test_data/macOS/clean/ls.mdiff b/test_data/macOS/clean/ls.mdiff
index aab82ef3e..7d8202b53 100644
--- a/test_data/macOS/clean/ls.mdiff
+++ b/test_data/macOS/clean/ls.mdiff
@@ -1,16 +1,18 @@
-## Changed: macOS/clean/ls [🟡 MEDIUM → 🟢 LOW]
+## Deleted: ls.x86_64 [🟡 MEDIUM]
-### 1 new behaviors
+| RISK | KEY | DESCRIPTION | EVIDENCE |
+|---------|--------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| -MEDIUM | [process/name_set](https://github.com/chainguard-dev/malcontent/blob/main/rules/process/name-set.yara#__progname) | [get or set the current process name](https://stackoverflow.com/questions/273691/using-progname-instead-of-argv0) | [__progname](https://github.com/search?q=__progname&type=code) |
+| -LOW | [discover/system/hostname_get](https://github.com/chainguard-dev/malcontent/blob/main/rules/discover/system/hostname-get.yara#gethostname) | [get computer host name](https://man7.org/linux/man-pages/man2/sethostname.2.html) | [gethostname](https://github.com/search?q=gethostname&type=code) |
+| -LOW | [exec/shell/TERM](https://github.com/chainguard-dev/malcontent/blob/main/rules/exec/shell/TERM.yara#TERM) | [Look up or override terminal settings](https://www.gnu.org/software/gettext/manual/html_node/The-TERM-variable.html) | [TERM](https://github.com/search?q=TERM&type=code) |
+| -LOW | [fs/link_read](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/link-read.yara#readlink) | [read value of a symbolic link](https://man7.org/linux/man-pages/man2/readlink.2.html) | [readlink](https://github.com/search?q=readlink&type=code) |
+| -LOW | [net/url/embedded](https://github.com/chainguard-dev/malcontent/blob/main/rules/net/url/embedded.yara#https_url) | contains embedded HTTPS URLs | [https://gnu.org/licenses/gpl.html](https://gnu.org/licenses/gpl.html)
[https://translationproject.org/team/](https://translationproject.org/team/)
[https://wiki.xiph.org/MIME_Types_and_File_Extensions](https://wiki.xiph.org/MIME_Types_and_File_Extensions)
[https://www.gnu.org/software/coreutils/](https://www.gnu.org/software/coreutils/) |
-| RISK | KEY | DESCRIPTION | EVIDENCE |
-|------|------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| +LOW | **[fs/directory/traverse](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/directory/directory-traverse.yara#fts)** | traverse filesystem hierarchy | [_fts_children](https://github.com/search?q=_fts_children&type=code)
[_fts_close](https://github.com/search?q=_fts_close&type=code)
[_fts_open](https://github.com/search?q=_fts_open&type=code)
[_fts_read](https://github.com/search?q=_fts_read&type=code)
[_fts_set](https://github.com/search?q=_fts_set&type=code) |
+## Added: ls [🟢 LOW]
-### 3 removed behaviors
-
-| RISK | KEY | DESCRIPTION | EVIDENCE |
-|---------|--------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| -MEDIUM | [process/name_set](https://github.com/chainguard-dev/malcontent/blob/main/rules/process/name-set.yara#__progname) | [get or set the current process name](https://stackoverflow.com/questions/273691/using-progname-instead-of-argv0) | [__progname](https://github.com/search?q=__progname&type=code) |
-| -LOW | [discover/system/hostname_get](https://github.com/chainguard-dev/malcontent/blob/main/rules/discover/system/hostname-get.yara#gethostname) | [get computer host name](https://man7.org/linux/man-pages/man2/sethostname.2.html) | [gethostname](https://github.com/search?q=gethostname&type=code) |
-| -LOW | [net/url/embedded](https://github.com/chainguard-dev/malcontent/blob/main/rules/net/url/embedded.yara#https_url) | contains embedded HTTPS URLs | [https://gnu.org/licenses/gpl.html](https://gnu.org/licenses/gpl.html)
[https://translationproject.org/team/](https://translationproject.org/team/)
[https://wiki.xiph.org/MIME_Types_and_File_Extensions](https://wiki.xiph.org/MIME_Types_and_File_Extensions)
[https://www.gnu.org/software/coreutils/](https://www.gnu.org/software/coreutils/) |
+| RISK | KEY | DESCRIPTION | EVIDENCE |
+|------|------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| +LOW | **[exec/shell/TERM](https://github.com/chainguard-dev/malcontent/blob/main/rules/exec/shell/TERM.yara#TERM)** | [Look up or override terminal settings](https://www.gnu.org/software/gettext/manual/html_node/The-TERM-variable.html) | [TERM](https://github.com/search?q=TERM&type=code) |
+| +LOW | **[fs/directory/traverse](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/directory/directory-traverse.yara#fts)** | traverse filesystem hierarchy | [_fts_children](https://github.com/search?q=_fts_children&type=code)
[_fts_close](https://github.com/search?q=_fts_close&type=code)
[_fts_open](https://github.com/search?q=_fts_open&type=code)
[_fts_read](https://github.com/search?q=_fts_read&type=code)
[_fts_set](https://github.com/search?q=_fts_set&type=code) |
+| +LOW | **[fs/link_read](https://github.com/chainguard-dev/malcontent/blob/main/rules/fs/link-read.yara#readlink)** | [read value of a symbolic link](https://man7.org/linux/man-pages/man2/readlink.2.html) | [readlink](https://github.com/search?q=readlink&type=code) |
diff --git a/test_data/macOS/clean/ls.sdiff.level_2 b/test_data/macOS/clean/ls.sdiff.level_2
index db7b91c5d..fa0ab56fa 100644
--- a/test_data/macOS/clean/ls.sdiff.level_2
+++ b/test_data/macOS/clean/ls.sdiff.level_2
@@ -1,2 +1,3 @@
-*** changed: macOS/clean/ls
+--- missing: ls.x86_64
-process/name_set
+++++ added: ls
diff --git a/test_data/macOS/clean/ls.sdiff.trigger_2 b/test_data/macOS/clean/ls.sdiff.trigger_2
index f700d8f2d..f4840559b 100644
--- a/test_data/macOS/clean/ls.sdiff.trigger_2
+++ b/test_data/macOS/clean/ls.sdiff.trigger_2
@@ -1,5 +1,10 @@
-*** changed: macOS/clean/ls
+--- missing: ls.x86_64
-discover/system/hostname_get
-+fs/directory/traverse
+-exec/shell/TERM
+-fs/link_read
-net/url/embedded
-process/name_set
+++++ added: ls
++exec/shell/TERM
++fs/directory/traverse
++fs/link_read
diff --git a/test_data/macOS/clean/ls.sdiff.trigger_3 b/test_data/macOS/clean/ls.sdiff.trigger_3
index e69de29bb..f4840559b 100644
--- a/test_data/macOS/clean/ls.sdiff.trigger_3
+++ b/test_data/macOS/clean/ls.sdiff.trigger_3
@@ -0,0 +1,10 @@
+--- missing: ls.x86_64
+-discover/system/hostname_get
+-exec/shell/TERM
+-fs/link_read
+-net/url/embedded
+-process/name_set
+++++ added: ls
++exec/shell/TERM
++fs/directory/traverse
++fs/link_read