T09 · Insecure Skill Coding Practices
- Location
client.go:218- Finding
Predictable world-readable debug files expose sensitive Lynx responses and permit symlink attacks
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a coherent Lynx Reservations CLI, but it needs review because it handles live credentials and can mutate travel documents while also exposing real credential and debug-data handling risks.
Install only if you trust the publisher and the Lynx account scope. Avoid running it from untrusted directories, do not use plaintext .env files casually, do not run the documented env | grep LYNX check, and keep LYNX_DEBUG unset unless you have a private machine and can securely remove debug files afterward.
client.go:218Predictable world-readable debug files expose sensitive Lynx responses and permit symlink attacks
gwt/build.go:5Unescaped user-controlled values are interpolated into pipe-delimited GWT-RPC requests
The README recommends loading secrets with export $(grep -v '^#' .env | xargs), an unsafe pattern that can expose credentials through shell parsing quirks, break on special characters, and encourage plaintext secret handling in a local file. In the context of a travel-system CLI using real Lynx credentials, mishandling these values can lead to credential disclosure and unauthorized access to itineraries, files, and uploaded documents.
Puis chargez-le :
export $(grep -v '^#' .env | xargs)
Ou utilisez direnv pour le chargement automatique.
The debug recipe env | grep LYNX will print authentication-related environment variables, including the password, directly to the terminal or logs. In an agent or recorded-session context, this can immediately expose live credentials to transcripts, shell history capture, CI logs, or other observers, enabling account compromise.
The documented .env auto-loader means the CLI automatically reads credentials from the working directory, creating an implicit secret-ingestion path. In shared or untrusted directories, an attacker could plant a .env file to influence which account is used, or cause accidental use of sensitive credentials without the operator realizing it.
├── lynx_architecture.md # Full architecture document (decisions, comparisons)
│
├── cmd/ # CLI commands — one file per command + dispatcher
│ ├── cmd.go # Command registry, dispatcher, .env auto-loader, config
│ ├── file_search_by_party_name.go
│ ├── file_search_by_file_reference.go
│ ├── retrieve_itinerary.go
This section explicitly documents that the program reads .env from the current working directory at startup. Because the skill authenticates to a real reservations system and supports data-modifying actions, implicit credential loading materially increases the risk of secret misuse, credential confusion, and attacker-controlled environment injection when run from untrusted project folders.
The `ParseFileSearchResponse` function uses **backward scanning**: it iterates from the last element backward, identifies `FileSearchResults` type markers, and extracts 10 fields per result. This approach correctly handles multi-result responses (tested with 10 results in `parse_test.go`).
### 2. .env Auto-Load (Convenience vs Security)
`cmd/cmd.go:13-33` implements a lightweight `.env` loader — no external dependency. It reads `.env` from the working directory at startup:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
}
func loadDotenv() {
data, err := os.ReadFile(".env")
if err != nil {
return
}
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
}
func loadDotenv() {
data, err := os.ReadFile(".env")
if err != nil {
return
}
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
├── go.mod # Module: dodmcdund.cc/lynx-travel-agent/lynxskill (Go 1.23.10)
├── go.sum
├── .gitignore # Ignores /bin/, /lynxskill
├── .env # Local credentials (gitignored?)
├── SKILL.md # OpenClaw skill definition (YAML frontmatter + docs)
├── README.md # User-facing documentation
├── lynx_architecture.md # This file
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
├── go.mod # Module: dodmcdund.cc/lynx-travel-agent/lynxskill (Go 1.23.10)
├── go.sum
├── .gitignore # Ignores /bin/, /lynxskill
├── .env # Local credentials (gitignored?)
├── SKILL.md # OpenClaw skill definition (YAML frontmatter + docs)
├── README.md # User-facing documentation
├── lynx_architecture.md # This file
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
├── go.mod # Module: dodmcdund.cc/lynx-travel-agent/lynxskill (Go 1.23.10)
├── go.sum
├── .gitignore # Ignores /bin/, /lynxskill
├── .env # Local credentials (gitignored?)
├── SKILL.md # OpenClaw skill definition (YAML frontmatter + docs)
├── README.md # User-facing documentation
├── lynx_architecture.md # This file
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
├── go.mod # Module: dodmcdund.cc/lynx-travel-agent/lynxskill (Go 1.23.10)
├── go.sum
├── .gitignore # Ignores /bin/, /lynxskill
├── .env # Local credentials (gitignored?)
├── SKILL.md # OpenClaw skill definition (YAML frontmatter + docs)
├── README.md # User-facing documentation
├── lynx_architecture.md # This file
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
├── go.mod # Module: dodmcdund.cc/lynx-travel-agent/lynxskill (Go 1.23.10)
├── go.sum
├── .gitignore # Ignores /bin/, /lynxskill
├── .env # Local credentials (gitignored?)
├── SKILL.md # OpenClaw skill definition (YAML frontmatter + docs)
├── README.md # User-facing documentation
├── lynx_architecture.md # This file
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
├── go.mod # Module: dodmcdund.cc/lynx-travel-agent/lynxskill (Go 1.23.10)
├── go.sum
├── .gitignore # Ignores /bin/, /lynxskill
├── .env # Local credentials (gitignored?)
├── SKILL.md # OpenClaw skill definition (YAML frontmatter + docs)
├── README.md # User-facing documentation
├── lynx_architecture.md # This file
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
### 2.1 `file_search_by_party_name`
| Champ | Valeur |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Nom MCP** | `file_search_by_party_name` |
| **Description** | Retrieve file from party name |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| Champ | Valeur |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Nom MCP** | `file_search_by_party_name` |
| **Description** | Retrieve file from party name |
| **Paramètres** | `partyName` (string, **required**) |
| **Endpoint** | `POST /lynx/service/file.rpc` |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| Champ | Valeur |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Nom MCP** | `file_search_by_party_name` |
| **Description** | Retrieve file from party name |
| **Paramètres** | `partyName` (string, **required**) |
| **Endpoint** | `POST /lynx/service/file.rpc` |
| **Méthode GWT** | `FileService.search(FileSearchCriteria)` |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| Champ | Valeur |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Nom MCP** | `file_search_by_party_name` |
| **Description** | Retrieve file from party name |
| **Paramètres** | `partyName` (string, **required**) |
| **Endpoint** | `POST /lynx/service/file.rpc` |
| **Méthode GWT** | `FileService.search(FileSearchCriteria)` |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Nom MCP** | `file_search_by_party_name` |
| **Description** | Retrieve file from party name |
| **Paramètres** | `partyName` (string, **required**) |
| **Endpoint** | `POST /lynx/service/file.rpc` |
| **Méthode GWT** | `FileService.search(FileSearchCriteria)` |
| **Réponse** | `{ count: int, results: Array<FileSearchResult> }` |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| **Description** | Retrieve file from party name |
| **Paramètres** | `partyName` (string, **required**) |
| **Endpoint** | `POST /lynx/service/file.rpc` |
| **Méthode GWT** | `FileService.search(FileSearchCriteria)` |
| **Réponse** | `{ count: int, results: Array<FileSearchResult> }` |
| **FileSearchResult** | `companyCode`, `clientIdentifier`, `clientReference`, `currency`, `fileIdentifier`, `fileReference`, `partyName`, `status`, `travelDate` |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| **Paramètres** | `partyName` (string, **required**) |
| **Endpoint** | `POST /lynx/service/file.rpc` |
| **Méthode GWT** | `FileService.search(FileSearchCriteria)` |
| **Réponse** | `{ count: int, results: Array<FileSearchResult> }` |
| **FileSearchResult** | `companyCode`, `clientIdentifier`, `clientReference`, `currency`, `fileIdentifier`, `fileReference`, `partyName`, `status`, `travelDate` |
### 2.2 `file_search_by_file_reference`
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
### 2.3 `retrieve_itinerary`
| Champ | Valeur |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Nom MCP** | `retrieve_itinerary` |
| **Description** | Retrieve file itinerary |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| Champ | Valeur |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Nom MCP** | `retrieve_itinerary` |
| **Description** | Retrieve file itinerary |
| **Paramètres** | `fileIdentifier` (string, **required**) |
| **Endpoint** | `POST /lynx/service/file.rpc` |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| Champ | Valeur |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Nom MCP** | `retrieve_itinerary` |
| **Description** | Retrieve file itinerary |
| **Paramètres** | `fileIdentifier` (string, **required**) |
| **Endpoint** | `POST /lynx/service/file.rpc` |
| **Méthode GWT** | `FileService.retrieveItinerary(Long)` |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Nom MCP** | `retrieve_itinerary` |
| **Description** | Retrieve file itinerary |
| **Paramètres** | `fileIdentifier` (string, **required**) |
| **Endpoint** | `POST /lynx/service/file.rpc` |
| **Méthode GWT** | `FileService.retrieveItinerary(Long)` |
| **Réponse** | `{ type, partyName, fileReference, fileIdentifier, clientIdentifier, agentReference, itineraryCount, itineraries: Array<ItineraryTransactionSummary> }` |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| **Nom MCP** | `retrieve_itinerary` |
| **Description** | Retrieve file itinerary |
| **Paramètres** | `fileIdentifier` (string, **required**) |
| **Endpoint** | `POST /lynx/service/file.rpc` |
| **Méthode GWT** | `FileService.retrieveItinerary(Long)` |
| **Réponse** | `{ type, partyName, fileReference, fileIdentifier, clientIdentifier, agentReference, itineraryCount, itineraries: Array<ItineraryTransactionSummary> }` |
| **ItineraryTransactionSummary** | `voucherIdentifier`, `date`, `transactionIdentifier`, `supplier`, `status`, `confirmationNumber`, `location` |
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
| **Description** | Retrieve file itinerary |
| **Paramètres** | `fileIdentifier` (string, **required**) |
| **Endpoint** | `POST /lynx/service/file.rpc` |
| **Méthode GWT** | `FileService.retrieveItinerary(Long)` |
| **Réponse** | `{ type, partyName, fileReference, fileIdentifier, clientIdentifier, agentReference, itineraryCount, itineraries: Array<ItineraryTransactionSummary> }` |
| **ItineraryTransactionSummary** | `voucherIdentifier`, `date`, `transactionIdentifier`, `supplier`, `status`, `confirmationNumber`, `location` |
No suspicious patterns detected.