Skip to content

About

Customized toolbox containing materials to perform a secure code review with the help of a coding assistant.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

MadeWitVSCode

Description

πŸ—ƒοΈ All skills (Claude Code proprietary format, stored as SKILL.md files and invoked as slash commands) are stored into this folder.

πŸ§‘β€πŸ’» This folder contains coding assistant skills that I use to perform a secure code review.

πŸ”¬ The idea is to:

  1. Learn how to leverage AI, via a coding assistant (claude code here), in the context of a secure code review activity.
  2. Define a process to perform a secure code review with the help of AI via a coding assistant.
  3. Allow me to learn how to create instructions for a coding assistant to help me during a secure code review activity.

Toolbox usage approach

sequenceDiagram
    actor Me as Dom
    participant R1 as code-snippets-security-utils
    participant R2 as code-assistant-skills-security-utils
    participant R3 as toolbox-ai-assisted-secure-code-review

    Me->>Me: Find a weakness during<br/>a secure code review.
    alt Remediation not documented<br/>into the repository
        Me->>R1: Search, test, and create a new code snippet<br/>with a remediation proposal.
        R1->>Me: Test and publishing OK.
    end
    alt Skill do not exist<br/>into the repository<br/>"code-assistant-skills-security-utils"
        Me->>R2: Use the test work done to create the corresponding skill<br/>to generate code that prevents the weakness by default.
        R2->>Me: Test and publishing OK.
    end
    alt New skill created into the repository<br/>"code-assistant-skills-security-utils"
        Me->>R3: Look to create, if relevant, a new dedicated agent using<br/>the content of the new skill created<br/>to detect the corresponding weakness.
        R3->>Me: Test and publishing OK.
    end        
    alt Weakness not detected by the skill "codebase-hotspotsv2"<br/>so manually identified
        Me->>R3: Update the skill to detect the weakness.
        R3->>Me: Test and publishing OK.
        Me->>R1: Create a code snippet for the corresponding remediation.
        R1->>Me: Test and publishing OK.
        Me->>R2: Create a skill for the corresponding weakness.
        R2->>Me: Test and publishing OK.
    end
Loading

πŸ“¦ Related GitHub repositories:

Review process

πŸ”¬ I imagined the following process against a codebase using claude code sessions:

πŸ§‘β€πŸ’» Intital steps into a claude code session at the root folder of the codebase:

  1. Start a new claude code session: Important to isolate the processing from a context perspective.
  2. Invoke the skill /codebase-overview to have a global visual overview of the risky sinks.

πŸ§‘β€πŸ’» For each module of the codebase into a claude code session at the root folder of the module, apply these steps:

  1. Scan the code with SemGrep to identify issues using a pattern-based approach: Goal is to identify issues not linked to an entry point, like for example, a deprecated algorithm used but not called from an entry point.
  2. Start a new claude code session: Important to isolate the processing from a context perspective.
  3. Invoke the skill /codebase-semgrep-findings-review to filter false positive findings from the SemGrep scan results.
  4. Start a new claude code session: Important to isolate the processing from a context perspective.
  5. Invoke the skill /codebase-hotspotsv2 to identify entry point that leads to risk processing from a security perspective.
  6. Review and manually validate the result of step 3 + step 5 with the help of the skill /codebase-review-buddy.

⚠️ Important notes:

  • An approach module by module is used to speed up the review.
  • The SemGrep scan is performed via this dedicated toolbox.

Origin of the creation of the skills based on different cases (context)

Case 1: Codebase overview

πŸ€” In this case, the context is that I received a codebase and I want to use claude code to give me the following overview:

A visual overview of the information entry points and where the information land including the type of processing
and if such processing can be risky from a security perspective.

πŸ“¦ User prompt is stored, as a claude code skill, into the file in the folder .claude/skills/codebase-overview/ (ref).

πŸ€– Use it via this instruction inside a claude code session: /codebase-overview [RELATIVE_PATH_TO_CODEBASE].

βœ… The generated Mermaid code was validated using the Mermaid Live editor to check its rendering, readability, and the effectiveness of the generated diagram. The Mermaid format was chosen because it is a text-based format; it can therefore be modified after generation if necessary or sent to an LLM for additional analysis rounds.

ℹ️ Forms legend:

  • Hexagon form represents a entry point.
  • Rectangle form represents a custom code landing points with a TAG to indicate the type of processing performed and colored if such processing can be risky from a security perspective.
  • Circle form represents a third-party library landing points and colored if processing performed can be risky from a security perspective.

ℹ️ Node label naming conventions is defined into the section Output rules section of the skill file.

πŸ”¬ Example of generated schema against the source code of OWASP WebGoat using the download of a zip archive of the main branch:

flowchart LR
    MAIN{{"StartWebGoat#main"}} --> LIB_SB(("Spring Boot"))
    HH{{"HammerHead#attack"}} --> P_SESSION["org.owasp.webgoat.container.session -- SESSION"]:::med
    REG{{"RegistrationController#registration"}} --> P_USERS["org.owasp.webgoat.container.users -- USER-MGMT -> AUTHN"]:::med
    REGO{{"RegistrationController#registrationOAUTH"}} --> P_USERS
    RPT{{"ReportCardController#reportCard"}} --> P_USERS
    MENU{{"LessonMenuService#showLeftNav"}} --> P_USERS
    PROG{{"LessonProgressService#lessonOverview"}} --> P_USERS
    RESTART{{"RestartLessonService#restartLesson"}} --> LIB_FLYWAY(("Flyway")):::high
    ENVSVC{{"EnvironmentService#homeDirectory"}} --> P_ENV["org.owasp.webgoat.container.service -- CONFIG-EXPOSURE"]:::med
    LBLDBG{{"LabelDebugService#setDebuggingStatus"}} --> P_ENV
    LBL{{"LabelService#fetchLabels"}} --> P_I18N["org.owasp.webgoat.container.i18n -- METADATA/I18N"]
    HINT{{"HintService#getHints"}} --> P_I18N
    FS_IMP{{"FileServer#importFile"}} --> LIB_FILE(("java.io / java.nio (file I/O)")):::high
    FS_GET{{"FileServer#getFiles"}} --> LIB_FILE
    MAIL{{"MailboxController#sendEmail"}} --> LIB_MAIL(("Spring Mail"))
    WJWT_D{{"JWTController#decode"}} --> LIB_JJWT(("io.jsonwebtoken (jjwt)")):::med
    WJWT_E{{"JWTController#encode"}} --> LIB_JJWT
    VERIFY{{"VerifyAccount#completed"}} --> P_AUTHBYPASS["org.owasp.webgoat.lessons.authbypass -- AUTHN"]:::med
    A1{{"Assignment1#completed"}} --> P_CHAL["org.owasp.webgoat.lessons.challenges -- AUTHN -> ACCOUNT-RECOVERY"]:::med
    A7R{{"Assignment7#resetPassword"}} --> P_CHAL
    A8V{{"Assignment8#vote"}} --> P_CHAL
    IMG{{"ImageServlet#logo"}} --> LIB_FILE
    A5{{"Assignment5#login"}} --> LIB_JDBC(("java.sql / JDBC")):::high
    A7L{{"Assignment7#sendPasswordResetLink"}} --> LIB_REST(("Spring RestTemplate")):::med
    ENC{{"EncodingAssignment#completed"}} --> P_CRYPTO["org.owasp.webgoat.lessons.cryptography -- CRYPTO"]:::med
    HMD5{{"HashingAssignment#getMd5"}} --> LIB_CRYPTO(("java.security / javax.crypto")):::med
    HSHA{{"HashingAssignment#getSha256"}} --> LIB_CRYPTO
    SDEF{{"SecureDefaultsAssignment#completed"}} --> LIB_CRYPTO
    SIGN{{"SigningAssignment#completed"}} --> LIB_CRYPTO
    SIGNK{{"SigningAssignment#getPrivateKey"}} --> LIB_CRYPTO
    FR_R{{"ForgedReviews#retrieveReviews"}} --> P_CSRF["org.owasp.webgoat.lessons.csrf -- CSRF/STATE-CHANGE"]:::med
    FR_C{{"ForgedReviews#createNewReview"}} --> P_CSRF
    DESER{{"InsecureDeserializationTask#completed"}} --> LIB_OIS(("java.io.ObjectInputStream")):::high
    HIJACK{{"HijackSessionAssignment#login"}} --> P_HIJACK["org.owasp.webgoat.lessons.hijacksession.cas -- AUTHN -> SESSION"]:::med
    IDOR_V{{"IDORViewOtherProfile#completed"}} --> P_IDOR["org.owasp.webgoat.lessons.idor -- AUTHZ -> ACCESS-CONTROL"]:::med
    IDOR_E{{"IDOREditOtherProfile#completed"}} --> P_IDOR
    IDOR_O{{"IDORViewOwnProfile#invoke"}} --> P_IDOR
    IDOR_L{{"IDORLogin#completed"}} --> P_IDOR
    INSLOG{{"InsecureLoginTask#completed"}} --> P_INSLOG["org.owasp.webgoat.lessons.insecurelogin -- AUTHN"]:::med
    JWT_DEC{{"JWTDecodeEndpoint#decode"}} --> P_JWT["org.owasp.webgoat.lessons.jwt -- AUTHN -> SESSION"]:::med
    JWT_SK{{"JWTSecretKeyEndpoint#login"}} --> LIB_JJWT
    JWT_RF{{"JWTRefreshEndpoint#newToken"}} --> LIB_JJWT
    JWT_VT{{"JWTVotesEndpoint#vote"}} --> LIB_JJWT
    JWT_JKU{{"JWTHeaderJKUEndpoint#resetVotes"}} --> LIB_AUTH0(("com.auth0.jwt")):::med
    JWT_KID{{"JWTHeaderKIDEndpoint#resetVotes"}} --> LIB_JDBC
    JWT_KID --> LIB_JJWT
    LOGSP{{"LogSpoofingTask#completed"}} --> P_LOG["org.owasp.webgoat.lessons.logging -- LOG-INJECTION"]
    LOGBL{{"LogBleedingTask#completed"}} --> LIB_SLF4J(("slf4j"))
    MAC_L{{"MissingFunctionACUsers#listUsers"}} --> P_MAC["org.owasp.webgoat.lessons.missingac -- AUTHZ -> ACCESS-CONTROL"]:::med
    MAC_S{{"MissingFunctionACUsers#usersService"}} --> LIB_JDBC
    MAC_A{{"MissingFunctionACUsers#addUser"}} --> LIB_JDBC
    MAC_H{{"MissingFunctionACHiddenMenus#completed"}} --> P_MAC
    OR1{{"OpenRedirectTask1#simulate"}} --> P_REDIR["org.owasp.webgoat.lessons.openredirect -- REDIRECT"]:::med
    OR4{{"OpenRedirectTask4#doubleDecode"}} --> P_REDIR
    ORR{{"OpenRedirectRealRedirect#real"}} --> P_REDIR
    PWL{{"ResetLinkAssignment#login"}} --> P_PWR["org.owasp.webgoat.lessons.passwordreset -- ACCOUNT-RECOVERY"]:::med
    PWC{{"ResetLinkAssignment#changePassword"}} --> P_PWR
    PWQ{{"SecurityQuestionAssignment#completed"}} --> P_PWR
    PWSML{{"SimpleMailAssignment#login"}} --> P_PWR
    PWSEND{{"ResetLinkAssignmentForgotPassword#sendPasswordResetLink"}} --> LIB_REST
    PU_UP{{"ProfileUpload#uploadFileHandler"}} --> LIB_FILE
    PU_GET{{"ProfileUpload#getProfilePicture"}} --> LIB_FILE
    PUF_UP{{"ProfileUploadFix#uploadFileHandler"}} --> LIB_FILE
    PUR_GET{{"ProfileUploadRetrieval#getProfilePicture"}} --> LIB_FILE
    PZ_UP{{"ProfileZipSlip#uploadFileHandler"}} --> LIB_ZIP(("java.util.zip")):::high
    PZ_GET{{"ProfileZipSlip#getProfilePicture"}} --> LIB_FILE
    SECPW{{"SecurePasswordsAssignment#completed"}} --> LIB_ZXCVBN(("Zxcvbn"))
    ACT_E{{"ActuatorExposureTask#actuatorEnv"}} --> P_SECMC["org.owasp.webgoat.lessons.securitymisconfiguration -- CONFIG-EXPOSURE"]:::med
    ACT_K{{"ActuatorExposureTask#submitApiKey"}} --> P_SECMC
    SPOOF{{"SpoofCookieAssignment#login"}} --> P_SPOOF["org.owasp.webgoat.lessons.spoofcookie -- SESSION -> CRYPTO"]:::med
    SQL2{{"SqlInjectionLesson2#completed"}} --> LIB_JDBC
    SQL5{{"SqlInjectionLesson5#completed"}} --> LIB_JDBC
    SQL8{{"SqlInjectionLesson8#completed"}} --> LIB_JDBC
    SQL10{{"SqlInjectionLesson10#completed"}} --> LIB_JDBC
    SQL13{{"SqlInjectionLesson13#completed"}} --> LIB_JDBC
    SQLC{{"SqlInjectionChallenge#registerNewUser"}} --> LIB_JDBC
    SQLCL{{"SqlInjectionChallengeLogin#login"}} --> LIB_JDBC
    SQL6A{{"SqlInjectionLesson6a#completed"}} --> LIB_JDBC
    SQLIV{{"SqlOnlyInputValidation#attack"}} --> LIB_JDBC
    SQL10B{{"SqlInjectionLesson10b#completed"}} --> LIB_JAVAC(("javax.tools.JavaCompiler")):::high
    VULN{{"VulnerableComponentsLesson#completed"}} --> LIB_XSTREAM(("XStream")):::high
    XSS5{{"CrossSiteScriptingLesson5a#completed"}} --> P_XSS["org.owasp.webgoat.lessons.xss -- XSS-SINK"]
    XSS_ST{{"StoredXssComments#retrieveComments"}} --> P_XSS
    XSS3{{"CrossSiteScriptingLesson3#completed"}} --> LIB_JSOUP(("Jsoup"))
    XXE_S{{"SimpleXXE#createNewComment"}} --> LIB_XML(("javax.xml (StAX/XXE)")):::high
    XXE_B{{"BlindSendFileAssignment#addComment"}} --> LIB_XML
    XXE_C{{"ContentTypeAssignment#createNewUser"}} --> LIB_XML
    XXE_R{{"CommentsEndpoint#retrieveComments"}} --> P_XXE["org.owasp.webgoat.lessons.xxe -- XML-PARSE"]:::high
    SSRF2{{"SSRFTask2#completed"}} --> LIB_NET(("java.net.URL")):::high
    classDef high fill:#fdd,stroke:#c00,color:#900
    classDef med fill:#ffe9c7,stroke:#e08e00
Loading

Case 2: Codebase hotspots

Tip

The skill /codebase-hotspotsv2 (ref) is an evolution of the V1 that spawns dedicated agents per vulnerability class to enforce complete, class-specific detection rules that a general model tends to miss or apply inconsistently. It must be privileged over the V1.

πŸ€” In this case, the context is that I received a codebase and I want to use claude code to give point to code that does risky processing from a security perspective (called hotspot).

πŸ“¦ User prompt is stored, as a claude code skill, into the file in the folder .claude/skills/codebase-hotspotsv2/ (ref).

πŸ€– Use it via this instruction inside a claude code session: /codebase-hotspotsv2 [RELATIVE_PATH_TO_CODEBASE].

Case 3: Review the SemGrep scan of the codebase

πŸ€” In this case, I scanned the codebase with SemGrep to identify issues not linked to an entry point, like for example, a deprecated algorithm used but not called from an entry point.

πŸ“¦ User prompt is stored, as a claude code skill, into the file in the folder .claude/skills/codebase-semgrep-findings-review/ (ref).

πŸ€– Use it via this instruction inside a claude code session: /codebase-semgrep-findings-review [PATH_TO_SEMGREP_REPORT] [RELATIVE_PATH_TO_CODEBASE] [MINIMUM_CONFIDENCE_LEVEL].

πŸ’‘ [MINIMUM_CONFIDENCE_LEVEL]: Minimum confidence threshold for inclusion in output, accepted values are:

  • CONFIRMED: Only confirmed findings.
  • PARTIAL: Confirmed + needs-human-review findings.
  • Default: PARTIAL - FALSE_POSITIVE verdicts are always excluded from the findings list but are recorded in the summary table.

Case 4: Coding assistant buddy to analyze a finding or a code section

Note

The skill has instruction to try to prevent the model of the coding assistant to have a confirmation bias problem. The instruction allows the coding assistant to search for grounded proof from the codebase and the documentation to truly reply to the hypothesis or question asked. It helps me to use the current coding assistant session to deep dive about my hypothesis.

πŸ€” In this case, I have one of the following elements. I want to analyze the behavior of the feature to validate or invalidate the presence of an issue/risk from a security perspective:

  • The filtered findings from SemGrep.
  • The findings from the codebase-hotspotsv2 skills.
  • A doubt about a code snippet that seems dangerous or strange for me.

πŸ“¦ User prompt is stored, as a claude code skill, into the file in the folder .claude/skills/codebase-review-buddy/ (ref).

πŸ€– Use it via this instruction inside a claude code session: /codebase-review-buddy [FILE_PATH] [LINE_NUMBER] "[HYPOTHESIS_OR_QUESTION]".

Compatibility note

⚠️ The SKILL.md files use the Claude Code skill format (Anthropic proprietary) and cannot be validated with skills-ref (pip install skills-ref), which enforces the agentskills.io open specification. Claude Code-specific frontmatter fields (argument-hint, disable-model-invocation, etc.) are not allowed by that specification.

Install

πŸ§‘β€πŸ’» Copy the folder .claude/skills into the folder .claude of the project to review and use skills from a claude code session.

πŸ’‘ The script install.ps1 can be used too:

irm https://raw.githubusercontent.com/righettod/toolbox-ai-assisted-secure-code-review/main/install.ps1 | iex

Convert skills to other coding assistants

Important

Apply the steps indicated after having installed the Claude code skills inside the current folder.

πŸ€– Use the user prompt Please execute the conversion of Claude skills to "[CODING_ASSISTANT_NAME]" format as described in the "[INSTRUCTION_MD_FILE_NAME]" file. to initiate the conversion.

Vibe

  1. Download the file CONVERT_CLAUDE_SKILLS_TO_VIBE.md inside the current folder.
  2. Start a vibe session from the current folder.
  3. Use the user prompt above with the following variable:
  • [CODING_ASSISTANT_NAME] to Vibe CLI.
  • [INSTRUCTION_MD_FILE_NAME] to CONVERT_CLAUDE_SKILLS_TO_VIBE.md.

Finally, exit and restart a new session from the current folder.

Coding assistants error troubleshooting

Vibe

🐞 Error: provider_message: Tool call id was ee61e87d-25d8-4bad-8e47-02939eb234c5 but must be a-z, A-Z, 0-9, with a length of 9.

ℹ️ Issue 1075 open.

πŸ’‘ Solution: Patch the file vibe/core/llm/backend/mistral.py using the instruction below.

  • Use this command to find the location of the file python -c "import vibe.core.llm.backend.mistral as m; print(m.__file__)".
  • Add this function at the top of the class MistralMapper and add the import re:
@staticmethod
def _normalize_tool_call_id(tool_id: str | None) -> str:
    """Mistral requires tool call IDs to be exactly 9 alphanumeric characters."""
    if not tool_id:
        return "000000000"
    clean = re.sub(r"[^a-zA-Z0-9]", "", tool_id)
    # Pad if somehow shorter than 9 after stripping
    clean = (clean + "000000000")[:9]
    return clean
  • In the function parse_tool_calls replace id=tool_call.id, by id=self._normalize_tool_call_id(tool_call.id),.
  • In the function prepare_message for Role.assistant replace id=tc.id, by id=self._normalize_tool_call_id(tc.id),.
  • In the function prepare_message for Role.tool replace tool_call_id=msg.tool_call_id, by tool_call_id=self._normalize_tool_call_id(msg.tool_call_id),.

References

About

Customized toolbox containing materials to perform a secure code review with the help of a coding assistant.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages