release interactsh v1.3.1#1343
Conversation
Bumps [github.com/projectdiscovery/gologger](https://github.com/projectdiscovery/gologger) from 1.1.67 to 1.1.68. - [Release notes](https://github.com/projectdiscovery/gologger/releases) - [Commits](projectdiscovery/gologger@v1.1.67...v1.1.68) --- updated-dependencies: - dependency-name: github.com/projectdiscovery/gologger dependency-version: 1.1.68 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [github.com/projectdiscovery/retryablehttp-go](https://github.com/projectdiscovery/retryablehttp-go) from 1.3.5 to 1.3.6. - [Release notes](https://github.com/projectdiscovery/retryablehttp-go/releases) - [Commits](projectdiscovery/retryablehttp-go@v1.3.5...v1.3.6) --- updated-dependencies: - dependency-name: github.com/projectdiscovery/retryablehttp-go dependency-version: 1.3.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [github.com/projectdiscovery/fastdialer](https://github.com/projectdiscovery/fastdialer) from 0.5.3 to 0.5.4. - [Release notes](https://github.com/projectdiscovery/fastdialer/releases) - [Commits](projectdiscovery/fastdialer@v0.5.3...v0.5.4) --- updated-dependencies: - dependency-name: github.com/projectdiscovery/fastdialer dependency-version: 0.5.4 dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
…dev/github.com/projectdiscovery/fastdialer-0.5.4 chore(deps): bump github.com/projectdiscovery/fastdialer from 0.5.3 to 0.5.4
…dev/github.com/projectdiscovery/retryablehttp-go-1.3.6 chore(deps): bump github.com/projectdiscovery/retryablehttp-go from 1.3.5 to 1.3.6
…dev/github.com/projectdiscovery/gologger-1.1.68 chore(deps): bump github.com/projectdiscovery/gologger from 1.1.67 to 1.1.68
Bumps [github.com/projectdiscovery/hmap](https://github.com/projectdiscovery/hmap) from 0.0.99 to 0.0.100. - [Release notes](https://github.com/projectdiscovery/hmap/releases) - [Commits](projectdiscovery/hmap@v0.0.99...v0.0.100) --- updated-dependencies: - dependency-name: github.com/projectdiscovery/hmap dependency-version: 0.0.100 dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
…dev/github.com/projectdiscovery/hmap-0.0.100 chore(deps): bump github.com/projectdiscovery/hmap from 0.0.99 to 0.0.100
…l-differentiation fix: differentiate HTTP vs HTTPS protocol in interactions
In wildcard mode, GetInteractionsWithId clears data on first poll, starving subsequent clients. Use per-consumer read offsets so each client independently tracks its position in the shared data buffer. Buffer cap is configurable via INTERACTSH_MAX_SHARED_INTERACTIONS env var (default 10000).
…hal-corruption fix: interaction data corruption causing unmarshal errors
Neo - PR Security ReviewNo security issues found Highlights
Comment |
WalkthroughBumps package and dependency versions, trims decrypted payloads before JSON unmarshalling, refactors servers to use jsoniter.Marshal and dynamic http/https detection, adds per-consumer storage APIs and eviction/compaction logic, extensive storage and round‑trip tests, and docs + env var for MaxSharedInteractions. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Server
participant StorageDB
participant LevelDB
Client->>Server: Poll or submit interaction (id, consumerID)
Server->>StorageDB: GetInteractionsWithIdForConsumer(id, consumerID)
StorageDB->>StorageDB: Check ReadOffsets / LastSeen, applyTrim/evict if needed
alt interactions in memory cache
StorageDB-->>Server: Return unseen interactions (bytes)
else interactions persisted
StorageDB->>LevelDB: Read persisted entries for id
LevelDB-->>StorageDB: Return bytes
StorageDB-->>Server: Return unseen interactions (bytes)
end
Server->>Client: Respond with interactions
Note right of StorageDB: RemoveConsumer(id, consumerID) compacts/cleans stored data
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
pkg/storage/roundtrip_test.go (1)
95-195: Consider extracting shared round-trip test logic.
TestFullRoundTripInMemoryandTestFullRoundTripDiskduplicate most setup/store/retrieve/assert code. A shared helper would reduce maintenance overhead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/storage/roundtrip_test.go` around lines 95 - 195, Both tests duplicate setup/store/retrieve/assert logic; extract a helper to run the common round-trip flow. Create a helper (e.g., runFullRoundTrip(t, store)) that accepts an object implementing the minimal interface used in the tests (methods: SetIDPublicKey, AddInteraction, GetInteractions, Close) or accept a constructor func that returns the storage from Options/New; move key generation, secret/correlationID creation, loop that marshals + AddInteraction, the GetInteractions/assertions, and the decryption/unmarshal/assert loop (using clientDecrypt) into that helper, then have TestFullRoundTripInMemory and TestFullRoundTripDisk call it with the in-memory instance (New(&Options{...})) and disk instance respectively.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/server/responder_server.go`:
- Around line 95-97: The warning log incorrectly says "dns interaction"; update
the log message in the Responder code path where AddInteractionWithId is called
(the gologger.Warning().Msgf call that follows
h.options.Storage.AddInteractionWithId(h.options.Token, data)) to use the
correct protocol label such as "responder interaction" (or "Responder
interaction") so operators see the correct source of the failure; leave the rest
of the call (including formatting of err) unchanged.
In `@pkg/server/smb_server.go`:
- Around line 107-109: The warning log in the SMB handler incorrectly refers to
"dns interaction"; update the message to reference SMB so logs are accurate:
change the gologger.Warning().Msgf call that follows
h.options.Storage.AddInteractionWithId(h.options.Token, data) to a message such
as "Could not store SMB interaction" (include the error value as before) so the
log accurately reflects the protocol and still includes the error details.
In `@pkg/storage/storagedb.go`:
- Around line 124-129: The delete call in the re-registration flow currently
swallows errors (s.db.Delete([]byte(correlationID), nil)), leaving stale
ciphertext on disk; modify the re-registration logic in storagedb.go to capture
the error returned by s.db.Delete, and handle it explicitly—either return the
error up the call stack or log it and fail the registration flow so callers know
disk cleanup failed; reference the UseDisk() check, the s.db.Delete call, and
the correlationID variable when locating the code to change.
---
Nitpick comments:
In `@pkg/storage/roundtrip_test.go`:
- Around line 95-195: Both tests duplicate setup/store/retrieve/assert logic;
extract a helper to run the common round-trip flow. Create a helper (e.g.,
runFullRoundTrip(t, store)) that accepts an object implementing the minimal
interface used in the tests (methods: SetIDPublicKey, AddInteraction,
GetInteractions, Close) or accept a constructor func that returns the storage
from Options/New; move key generation, secret/correlationID creation, loop that
marshals + AddInteraction, the GetInteractions/assertions, and the
decryption/unmarshal/assert loop (using clientDecrypt) into that helper, then
have TestFullRoundTripInMemory and TestFullRoundTripDisk call it with the
in-memory instance (New(&Options{...})) and disk instance respectively.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e3918008-10b2-4d4f-a428-7bca72f1090b
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (13)
go.modpkg/client/client.gopkg/options/utils.gopkg/server/dns_server.gopkg/server/ftp_server.gopkg/server/http_server.gopkg/server/http_server_test.gopkg/server/ldap_server.gopkg/server/responder_server.gopkg/server/smb_server.gopkg/server/smtp_server.gopkg/storage/roundtrip_test.gopkg/storage/storagedb.go
| gologger.Debug().Msgf("Responder Interaction: \n%s\n", string(data)) | ||
| if err := h.options.Storage.AddInteractionWithId(h.options.Token, data); err != nil { | ||
| gologger.Warning().Msgf("Could not store dns interaction: %s\n", err) |
There was a problem hiding this comment.
Correct protocol label in warning message.
Line 97 currently logs "dns interaction" from Responder code path, which can mislead operations.
Proposed fix
- gologger.Warning().Msgf("Could not store dns interaction: %s\n", err)
+ gologger.Warning().Msgf("Could not store responder interaction: %s\n", err)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| gologger.Debug().Msgf("Responder Interaction: \n%s\n", string(data)) | |
| if err := h.options.Storage.AddInteractionWithId(h.options.Token, data); err != nil { | |
| gologger.Warning().Msgf("Could not store dns interaction: %s\n", err) | |
| gologger.Debug().Msgf("Responder Interaction: \n%s\n", string(data)) | |
| if err := h.options.Storage.AddInteractionWithId(h.options.Token, data); err != nil { | |
| gologger.Warning().Msgf("Could not store responder interaction: %s\n", err) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@pkg/server/responder_server.go` around lines 95 - 97, The warning log
incorrectly says "dns interaction"; update the log message in the Responder code
path where AddInteractionWithId is called (the gologger.Warning().Msgf call that
follows h.options.Storage.AddInteractionWithId(h.options.Token, data)) to use
the correct protocol label such as "responder interaction" (or "Responder
interaction") so operators see the correct source of the failure; leave the rest
of the call (including formatting of err) unchanged.
| gologger.Debug().Msgf("SMB Interaction: \n%s\n", string(data)) | ||
| if err := h.options.Storage.AddInteractionWithId(h.options.Token, data); err != nil { | ||
| gologger.Warning().Msgf("Could not store dns interaction: %s\n", err) |
There was a problem hiding this comment.
Fix incorrect protocol name in error log.
Line 109 says "dns interaction" inside SMB handling, which is misleading during incident/debug analysis.
Proposed fix
- gologger.Warning().Msgf("Could not store dns interaction: %s\n", err)
+ gologger.Warning().Msgf("Could not store smb interaction: %s\n", err)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| gologger.Debug().Msgf("SMB Interaction: \n%s\n", string(data)) | |
| if err := h.options.Storage.AddInteractionWithId(h.options.Token, data); err != nil { | |
| gologger.Warning().Msgf("Could not store dns interaction: %s\n", err) | |
| gologger.Debug().Msgf("SMB Interaction: \n%s\n", string(data)) | |
| if err := h.options.Storage.AddInteractionWithId(h.options.Token, data); err != nil { | |
| gologger.Warning().Msgf("Could not store smb interaction: %s\n", err) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@pkg/server/smb_server.go` around lines 107 - 109, The warning log in the SMB
handler incorrectly refers to "dns interaction"; update the message to reference
SMB so logs are accurate: change the gologger.Warning().Msgf call that follows
h.options.Storage.AddInteractionWithId(h.options.Token, data) to a message such
as "Could not store SMB interaction" (include the error value as before) so the
log accurately reflects the protocol and still includes the error details.
| // Clear any stale data from a previous registration (e.g. after cache eviction | ||
| // and session restore). Old data would be encrypted with a different AES key | ||
| // and cause decryption failures on the client. | ||
| if s.Options.UseDisk() { | ||
| _ = s.db.Delete([]byte(correlationID), nil) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -n -C2 's\.db\.Delete\(' pkg/storage/storagedb.goRepository: projectdiscovery/interactsh
Length of output: 689
🏁 Script executed:
#!/bin/bash
sed -n '115,135p' pkg/storage/storagedb.goRepository: projectdiscovery/interactsh
Length of output: 702
🏁 Script executed:
#!/bin/bash
sed -n '100,135p' pkg/storage/storagedb.goRepository: projectdiscovery/interactsh
Length of output: 1249
🏁 Script executed:
#!/bin/bash
sed -n '90,105p' pkg/storage/storagedb.goRepository: projectdiscovery/interactsh
Length of output: 646
🏁 Script executed:
#!/bin/bash
rg -n 'func \(s \*StorageDB\) Get' pkg/storage/storagedb.go | head -5Repository: projectdiscovery/interactsh
Length of output: 390
🏁 Script executed:
#!/bin/bash
sed -n '274,300p' pkg/storage/storagedb.goRepository: projectdiscovery/interactsh
Length of output: 790
🏁 Script executed:
#!/bin/bash
sed -n '220,275p' pkg/storage/storagedb.goRepository: projectdiscovery/interactsh
Length of output: 1808
🏁 Script executed:
#!/bin/bash
sed -n '249,270p' pkg/storage/storagedb.goRepository: projectdiscovery/interactsh
Length of output: 709
Handle stale-data delete failures explicitly in re-registration flow.
On line 128, delete errors are swallowed. If disk cleanup fails during re-registration, stale ciphertext encrypted with the previous AES key remains on disk. On cache eviction and restore, this stale data gets read and causes decryption/unmarshal failures on the client, as noted in the preceding comment.
Proposed fix
// Clear any stale data from a previous registration (e.g. after cache eviction
// and session restore). Old data would be encrypted with a different AES key
// and cause decryption failures on the client.
if s.Options.UseDisk() {
- _ = s.db.Delete([]byte(correlationID), nil)
+ if err := s.db.Delete([]byte(correlationID), nil); err != nil && !errors.Is(err, leveldb.ErrNotFound) {
+ return errors.Wrap(err, "could not clear stale interaction data")
+ }
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@pkg/storage/storagedb.go` around lines 124 - 129, The delete call in the
re-registration flow currently swallows errors
(s.db.Delete([]byte(correlationID), nil)), leaving stale ciphertext on disk;
modify the re-registration logic in storagedb.go to capture the error returned
by s.db.Delete, and handle it explicitly—either return the error up the call
stack or log it and fail the registration flow so callers know disk cleanup
failed; reference the UseDisk() check, the s.db.Delete call, and the
correlationID variable when locating the code to change.
…ent-poll fix: wildcard server sends interactions to all clients
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
pkg/storage/storagedb.go (1)
131-133:⚠️ Potential issue | 🟠 MajorHandle stale-data cleanup errors in re-registration path.
Line 132 still ignores delete failures. If cleanup fails, stale data can persist and poll responses may include incompatible ciphertext.
Proposed patch
if s.Options.UseDisk() { - _ = s.db.Delete([]byte(correlationID), nil) + if err := s.db.Delete([]byte(correlationID), nil); err != nil { + return errors.Wrap(err, "could not clear stale interaction data") + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/storage/storagedb.go` around lines 131 - 133, The delete call for stale data currently swallows errors; update the re-registration cleanup in storagedb.go so the result of s.db.Delete([]byte(correlationID), nil) is checked and handled: capture the returned error from s.db.Delete, and either log it via the component logger or return it up the call path (depending on the surrounding function's error semantics) so failures to remove stale ciphertext are not ignored; look for the block that checks s.Options.UseDisk() and the symbols s.db.Delete and correlationID to locate and modify the code.
🧹 Nitpick comments (2)
cmd/interactsh-server/main.go (1)
257-261: Surface invalidINTERACTSH_MAX_SHARED_INTERACTIONSvalues.Right now invalid/non-positive env values are ignored silently, which makes config mistakes easy to miss. A warning keeps behavior safe while improving operability.
Proposed patch
if v := os.Getenv("INTERACTSH_MAX_SHARED_INTERACTIONS"); v != "" { - if n, err := strconv.Atoi(v); err == nil && n > 0 { - storeOptions.MaxSharedInteractions = n - } + n, err := strconv.Atoi(v) + if err != nil || n <= 0 { + gologger.Warning().Msgf("Ignoring invalid INTERACTSH_MAX_SHARED_INTERACTIONS=%q (must be a positive integer)", v) + } else { + storeOptions.MaxSharedInteractions = n + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cmd/interactsh-server/main.go` around lines 257 - 261, The code silently ignores invalid or non-positive INTERACTSH_MAX_SHARED_INTERACTIONS values; update the block that parses os.Getenv("INTERACTSH_MAX_SHARED_INTERACTIONS") so that when strconv.Atoi returns an error or the parsed n <= 0 you emit a warning (e.g., via log.Printf or the existing logger) indicating the invalid value and that the default will be used, and only set storeOptions.MaxSharedInteractions when err == nil && n > 0; reference the env var name and the storeOptions.MaxSharedInteractions field in the message so it's easy to trace.pkg/server/http_server.go (1)
426-433: Consider surfacing consumer cleanup failures during deregistration.
RemoveConsumererrors are currently discarded. Logging at least warnings would make cleanup issues diagnosable.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/server/http_server.go` around lines 426 - 433, Replace the ignored RemoveConsumer calls with error handling: assign the result of h.options.Storage.RemoveConsumer(...) to err, and if err != nil emit a warning that includes the domain or token and r.CorrelationID so failures are diagnosable; use your existing logger (e.g., h.logger or h.options.Logger) to call Warn/Warnf with a message like "failed removing consumer <domain|token> for correlation <id>: <err>" and fall back to log.Printf if no logger exists. Ensure you do this for both the loop over h.options.Domains (when h.options.RootTLD) and the h.options.Token path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/server/http_server.go`:
- Around line 468-477: The code is silently ignoring errors from storage calls
in the poll flow: update the blocks that call
h.options.Storage.GetInteractionsWithIdForConsumer (used for root TLDs and for
h.options.Token) to check the returned error instead of discarding it; if an
error is returned, propagate it (return it from the surrounding
handler/function) or at minimum log it and return an appropriate error response
so backend failures do not appear as partial success — update references to ID,
tlddata, extradata, and the h.options.RootTLD/h.options.Token branches to handle
and surface the error from GetInteractionsWithIdForConsumer.
In `@README.md`:
- Around line 705-708: Change the fenced code block from using the "console"
language with "$" prompts to a "bash" block without "$" prefixes: remove the
leading "$ " on the two lines referencing the INTERACTSH_MAX_SHARED_INTERACTIONS
environment variable and the interactsh-server command, and update the block
fence language from "console" to "bash" so the block becomes a plain bash
snippet (affecting the lines that set INTERACTSH_MAX_SHARED_INTERACTIONS and
call interactsh-server).
---
Duplicate comments:
In `@pkg/storage/storagedb.go`:
- Around line 131-133: The delete call for stale data currently swallows errors;
update the re-registration cleanup in storagedb.go so the result of
s.db.Delete([]byte(correlationID), nil) is checked and handled: capture the
returned error from s.db.Delete, and either log it via the component logger or
return it up the call path (depending on the surrounding function's error
semantics) so failures to remove stale ciphertext are not ignored; look for the
block that checks s.Options.UseDisk() and the symbols s.db.Delete and
correlationID to locate and modify the code.
---
Nitpick comments:
In `@cmd/interactsh-server/main.go`:
- Around line 257-261: The code silently ignores invalid or non-positive
INTERACTSH_MAX_SHARED_INTERACTIONS values; update the block that parses
os.Getenv("INTERACTSH_MAX_SHARED_INTERACTIONS") so that when strconv.Atoi
returns an error or the parsed n <= 0 you emit a warning (e.g., via log.Printf
or the existing logger) indicating the invalid value and that the default will
be used, and only set storeOptions.MaxSharedInteractions when err == nil && n >
0; reference the env var name and the storeOptions.MaxSharedInteractions field
in the message so it's easy to trace.
In `@pkg/server/http_server.go`:
- Around line 426-433: Replace the ignored RemoveConsumer calls with error
handling: assign the result of h.options.Storage.RemoveConsumer(...) to err, and
if err != nil emit a warning that includes the domain or token and
r.CorrelationID so failures are diagnosable; use your existing logger (e.g.,
h.logger or h.options.Logger) to call Warn/Warnf with a message like "failed
removing consumer <domain|token> for correlation <id>: <err>" and fall back to
log.Printf if no logger exists. Ensure you do this for both the loop over
h.options.Domains (when h.options.RootTLD) and the h.options.Token path.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 031d7127-ba55-4320-9a9b-6356ff9ac1ce
📒 Files selected for processing (8)
README.mdcmd/interactsh-server/main.gopkg/server/http_server.gopkg/storage/option.gopkg/storage/storage.gopkg/storage/storagedb.gopkg/storage/storagedb_test.gopkg/storage/types.go
| if h.options.RootTLD { | ||
| for _, domain := range h.options.Domains { | ||
| interactions, _ := h.options.Storage.GetInteractionsWithId(domain) | ||
| interactions, _ := h.options.Storage.GetInteractionsWithIdForConsumer(domain, ID) | ||
| // root domains interaction are not encrypted | ||
| tlddata = append(tlddata, interactions...) | ||
| } | ||
| } | ||
| if h.options.Token != "" { | ||
| // auth token interactions are not encrypted | ||
| extradata, _ = h.options.Storage.GetInteractionsWithId(h.options.Token) | ||
| extradata, _ = h.options.Storage.GetInteractionsWithIdForConsumer(h.options.Token, ID) |
There was a problem hiding this comment.
Do not silently ignore shared-data fetch errors in poll flow.
Line 470 and Line 477 ignore storage errors. That can return partial data as success and mask backend failures.
Proposed patch
if h.options.RootTLD {
for _, domain := range h.options.Domains {
- interactions, _ := h.options.Storage.GetInteractionsWithIdForConsumer(domain, ID)
+ interactions, err := h.options.Storage.GetInteractionsWithIdForConsumer(domain, ID)
+ if err != nil {
+ gologger.Warning().Msgf("Could not get root-tld interactions for %s and consumer %s: %s\n", domain, ID, err)
+ continue
+ }
// root domains interaction are not encrypted
tlddata = append(tlddata, interactions...)
}
}
if h.options.Token != "" {
// auth token interactions are not encrypted
- extradata, _ = h.options.Storage.GetInteractionsWithIdForConsumer(h.options.Token, ID)
+ extradata, err = h.options.Storage.GetInteractionsWithIdForConsumer(h.options.Token, ID)
+ if err != nil {
+ gologger.Warning().Msgf("Could not get token interactions for consumer %s: %s\n", ID, err)
+ }
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@pkg/server/http_server.go` around lines 468 - 477, The code is silently
ignoring errors from storage calls in the poll flow: update the blocks that call
h.options.Storage.GetInteractionsWithIdForConsumer (used for root TLDs and for
h.options.Token) to check the returned error instead of discarding it; if an
error is returned, propagate it (return it from the surrounding
handler/function) or at minimum log it and return an appropriate error response
so backend failures do not appear as partial success — update references to ID,
tlddata, extradata, and the h.options.RootTLD/h.options.Token branches to handle
and surface the error from GetInteractionsWithIdForConsumer.
| ```console | ||
| $ export INTERACTSH_MAX_SHARED_INTERACTIONS=50000 | ||
| $ interactsh-server -domain hackwithautomation.com -wildcard | ||
| ``` |
There was a problem hiding this comment.
Fix markdownlint MD014 in the new example block.
Lines 706-707 use shell prompts without output. Prefer a bash block without $ prefixes.
Proposed patch
-```console
-$ export INTERACTSH_MAX_SHARED_INTERACTIONS=50000
-$ interactsh-server -domain hackwithautomation.com -wildcard
+```bash
+export INTERACTSH_MAX_SHARED_INTERACTIONS=50000
+interactsh-server -domain hackwithautomation.com -wildcard</details>
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.21.0)</summary>
[warning] 706-706: Dollar signs used before commands without showing output
(MD014, commands-show-output)
---
[warning] 707-707: Dollar signs used before commands without showing output
(MD014, commands-show-output)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
Verify each finding against the current code and only fix it if needed.
In @README.md around lines 705 - 708, Change the fenced code block from using
the "console" language with "$" prompts to a "bash" block without "$" prefixes:
remove the leading "$ " on the two lines referencing the
INTERACTSH_MAX_SHARED_INTERACTIONS environment variable and the
interactsh-server command, and update the block fence language from "console" to
"bash" so the block becomes a plain bash snippet (affecting the lines that set
INTERACTSH_MAX_SHARED_INTERACTIONS and call interactsh-server).
</details>
<!-- fingerprinting:phantom:poseidon:hawk -->
<!-- This is an auto-generated comment by CodeRabbit -->
Add more control over custom DNS domains
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/server/dns_server.go`:
- Around line 656-665: The MX branch incorrectly treats record.Priority == 0 as
"unset" and forces a default of 10, preventing explicit zero priorities; update
the record representation to distinguish unset vs explicit zero (e.g., change
CustomRecordConfig.Priority to a pointer type like *uint16 or add an
IsPrioritySet boolean) and then modify the MX handling in dns_server.go to use
that sentinel (check record.Priority != nil or IsPrioritySet) and only apply the
default 10 when the priority is truly unset, keeping Preference set to 0 when
explicitly provided; ensure references to record.Priority in the MX case and any
record creation/parsing code are updated accordingly.
- Around line 633-650: In the "A" and "AAAA" handling blocks (case "A" / case
"AAAA") the code only checks net.ParseIP but doesn't validate address family:
for "A" ensure ip.To4() != nil before appending the dns.A record and return an
error if it's nil; for "AAAA" ensure ip.To4() == nil (i.e. not an IPv4 or
IPv4-mapped address) and ip.To16() != nil before appending the dns.AAAA record
and return an error if those checks fail; update the validation around
net.ParseIP, ip.To4(), ip.To16(), and the m.Answer append/use of dns.A and
dns.AAAA accordingly.
In `@README.md`:
- Line 251: The README contains a typo in the sentence describing supported
servers: replace the misspelled word "authencaited" with "authenticated" in the
paragraph that reads "supports other self-hosted public/authencaited interactsh
servers as well" so it becomes "supports other self-hosted public/authenticated
interactsh servers as well"; update that exact phrase in README.md.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5ef22914-813f-4a6c-91ae-c7eb0fe87d29
⛔ Files ignored due to path filters (1)
cmd/interactsh-server/example-custom-records.yamlis excluded by!**/*.yaml
📒 Files selected for processing (3)
README.mdpkg/server/dns_server.gopkg/server/dns_server_test.go
| case "A": | ||
| ip := net.ParseIP(record.Value) | ||
| if ip == nil { | ||
| return fmt.Errorf("invalid IPv4 address for A record: %s", record.Value) | ||
| } | ||
| m.Answer = append(m.Answer, &dns.A{ | ||
| Hdr: dns.RR_Header{Name: zone, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl}, | ||
| A: ip.To4(), | ||
| }) | ||
| case "AAAA": | ||
| ip := net.ParseIP(record.Value) | ||
| if ip == nil { | ||
| return fmt.Errorf("invalid IPv6 address for AAAA record: %s", record.Value) | ||
| } | ||
| m.Answer = append(m.Answer, &dns.AAAA{ | ||
| Hdr: dns.RR_Header{Name: zone, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl}, | ||
| AAAA: ip.To16(), | ||
| }) |
There was a problem hiding this comment.
Insufficient validation for A and AAAA record IP address types.
For A records: net.ParseIP succeeds for IPv6 addresses, but ip.To4() returns nil. The check on line 635 only verifies parsing succeeded, not that it's actually IPv4. This could result in appending an A record with A: nil.
For AAAA records: If an IPv4 address is provided, To16() returns an IPv4-mapped IPv6 address (::ffff:x.x.x.x), which may not be the intended behavior.
🐛 Proposed fix to validate address family
case "A":
ip := net.ParseIP(record.Value)
- if ip == nil {
+ ipv4 := ip.To4()
+ if ip == nil || ipv4 == nil {
return fmt.Errorf("invalid IPv4 address for A record: %s", record.Value)
}
m.Answer = append(m.Answer, &dns.A{
Hdr: dns.RR_Header{Name: zone, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl},
- A: ip.To4(),
+ A: ipv4,
})
case "AAAA":
ip := net.ParseIP(record.Value)
- if ip == nil {
+ if ip == nil || ip.To4() != nil {
return fmt.Errorf("invalid IPv6 address for AAAA record: %s", record.Value)
}
m.Answer = append(m.Answer, &dns.AAAA{📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case "A": | |
| ip := net.ParseIP(record.Value) | |
| if ip == nil { | |
| return fmt.Errorf("invalid IPv4 address for A record: %s", record.Value) | |
| } | |
| m.Answer = append(m.Answer, &dns.A{ | |
| Hdr: dns.RR_Header{Name: zone, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl}, | |
| A: ip.To4(), | |
| }) | |
| case "AAAA": | |
| ip := net.ParseIP(record.Value) | |
| if ip == nil { | |
| return fmt.Errorf("invalid IPv6 address for AAAA record: %s", record.Value) | |
| } | |
| m.Answer = append(m.Answer, &dns.AAAA{ | |
| Hdr: dns.RR_Header{Name: zone, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl}, | |
| AAAA: ip.To16(), | |
| }) | |
| case "A": | |
| ip := net.ParseIP(record.Value) | |
| ipv4 := ip.To4() | |
| if ip == nil || ipv4 == nil { | |
| return fmt.Errorf("invalid IPv4 address for A record: %s", record.Value) | |
| } | |
| m.Answer = append(m.Answer, &dns.A{ | |
| Hdr: dns.RR_Header{Name: zone, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl}, | |
| A: ipv4, | |
| }) | |
| case "AAAA": | |
| ip := net.ParseIP(record.Value) | |
| if ip == nil || ip.To4() != nil { | |
| return fmt.Errorf("invalid IPv6 address for AAAA record: %s", record.Value) | |
| } | |
| m.Answer = append(m.Answer, &dns.AAAA{ | |
| Hdr: dns.RR_Header{Name: zone, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl}, | |
| AAAA: ip.To16(), | |
| }) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@pkg/server/dns_server.go` around lines 633 - 650, In the "A" and "AAAA"
handling blocks (case "A" / case "AAAA") the code only checks net.ParseIP but
doesn't validate address family: for "A" ensure ip.To4() != nil before appending
the dns.A record and return an error if it's nil; for "AAAA" ensure ip.To4() ==
nil (i.e. not an IPv4 or IPv4-mapped address) and ip.To16() != nil before
appending the dns.AAAA record and return an error if those checks fail; update
the validation around net.ParseIP, ip.To4(), ip.To16(), and the m.Answer
append/use of dns.A and dns.AAAA accordingly.
| case "MX": | ||
| priority := record.Priority | ||
| if priority == 0 { | ||
| priority = 10 // default priority if not specified | ||
| } | ||
| m.Answer = append(m.Answer, &dns.MX{ | ||
| Hdr: dns.RR_Header{Name: zone, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: ttl}, | ||
| Mx: dns.Fqdn(record.Value), | ||
| Preference: priority, | ||
| }) |
There was a problem hiding this comment.
MX priority 0 cannot be explicitly set.
Priority 0 is a valid MX priority value (highest preference), but the code treats it as "unset" and defaults to 10. Users wanting to set priority 0 explicitly cannot do so.
Consider documenting this behavior, or using a pointer (*uint16) in CustomRecordConfig.Priority to distinguish "not set" from "explicitly zero".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@pkg/server/dns_server.go` around lines 656 - 665, The MX branch incorrectly
treats record.Priority == 0 as "unset" and forces a default of 10, preventing
explicit zero priorities; update the record representation to distinguish unset
vs explicit zero (e.g., change CustomRecordConfig.Priority to a pointer type
like *uint16 or add an IsPrioritySet boolean) and then modify the MX handling in
dns_server.go to use that sentinel (check record.Priority != nil or
IsPrioritySet) and only apply the default 10 when the priority is truly unset,
keeping Preference set to 0 when explicitly provided; ensure references to
record.Priority in the MX case and any record creation/parsing code are updated
accordingly.
| ## Interactsh Web Client | ||
|
|
||
| [Interactsh-web](https://github.com/projectdiscovery/interactsh-web) is a free and open-source web client that displays Interactsh interactions in a well-managed dashboard in your browser. It uses the browser's local storage to store and display all incoming interactions. By default, the web client is configured to use **interact.sh** as default interactsh server, and supports other self-hosted public/authencaited interactsh servers as well. | ||
| [Interactsh-web](https://github.com/projectdiscovery/interactsh-web) is a free and open-source web client that displays Interactsh interactions in a well-managed dashboard in your browser. It uses the browser's local storage to store and display all incoming interactions. By default, the web client is configured to use **oast.fun** as default interactsh server, and supports other self-hosted public/authencaited interactsh servers as well. |
There was a problem hiding this comment.
Fix typo: "authencaited" → "authenticated".
The word "authencaited" is misspelled and should be "authenticated".
📝 Proposed fix
-[Interactsh-web](https://github.com/projectdiscovery/interactsh-web) is a free and open-source web client that displays Interactsh interactions in a well-managed dashboard in your browser. It uses the browser's local storage to store and display all incoming interactions. By default, the web client is configured to use **oast.fun** as default interactsh server, and supports other self-hosted public/authencaited interactsh servers as well.
+[Interactsh-web](https://github.com/projectdiscovery/interactsh-web) is a free and open-source web client that displays Interactsh interactions in a well-managed dashboard in your browser. It uses the browser's local storage to store and display all incoming interactions. By default, the web client is configured to use **oast.fun** as default interactsh server, and supports other self-hosted public/authenticated interactsh servers as well.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| [Interactsh-web](https://github.com/projectdiscovery/interactsh-web) is a free and open-source web client that displays Interactsh interactions in a well-managed dashboard in your browser. It uses the browser's local storage to store and display all incoming interactions. By default, the web client is configured to use **oast.fun** as default interactsh server, and supports other self-hosted public/authencaited interactsh servers as well. | |
| [Interactsh-web](https://github.com/projectdiscovery/interactsh-web) is a free and open-source web client that displays Interactsh interactions in a well-managed dashboard in your browser. It uses the browser's local storage to store and display all incoming interactions. By default, the web client is configured to use **oast.fun** as default interactsh server, and supports other self-hosted public/authenticated interactsh servers as well. |
🧰 Tools
🪛 LanguageTool
[grammar] ~251-~251: Ensure spelling is correct
Context: ..., and supports other self-hosted public/authencaited interactsh servers as well. A hosted i...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@README.md` at line 251, The README contains a typo in the sentence describing
supported servers: replace the misspelled word "authencaited" with
"authenticated" in the paragraph that reads "supports other self-hosted
public/authencaited interactsh servers as well" so it becomes "supports other
self-hosted public/authenticated interactsh servers as well"; update that exact
phrase in README.md.
closes #1342
Summary by CodeRabbit
Chores
New Features
Bug Fixes
Tests