Skip to content

Duo VR - Missing vulnerability_description input

This bug has been discovered during the Evaluation of Claude 3.7 (#525295 - closed), but it's not specific to Claude 3.7 and is probably in production for an unknown period of time.

Bug description

The vulnerability_description input is not provided to the AI Gateway when Vulnerability Resolution in triggered.
This happens for all the vulnerabilities, of all CWEs.
This missing description is hurting the quality of the results of Vulnerability Resolution, as the LLM doesn't have proper context about

Actual behavior

The vulnerability_description input is missing when calling the AI Gateway.
Here is an example, extracted from the logs:

      "body": {
        "prompt_version": "0.0.1-dev",
        "inputs": {
          "identifiers": "<report_identifiers>\n * A1:2017 - Injection\n* Flawfinder - strncpy\n* flawfinder.strncpy-1\n* CWE-120\n* A03:2021 - Injection\n</report_identifiers>",
          "vulnerable_code": "                strncpy(msg, _msg[i], OS_SIZE_1024);",
          "source_code": "/* @(#) $Id: ./src/remoted/manager.c, 2011/09/08 dcid Exp $\n */\n\n/* Copyright (C) 2009 Trend Micro Inc.\n * All right reserved.\n *\n * This program is a free software; you can redistribute it\n * and/or modify it under the terms of the GNU General Public\n * License (version 2) as published by the FSF - Free Software\n * Foundation\n */\n\n#include \"shared.h\"\n#include <pthread.h>\n\n#include \"remoted.h\"\n#include \"os_net/os_net.h\"\n#include \"os_crypto/md5/md5_op.h\"\n\n\n/* Internal structures */\ntypedef struct _file_sum\n{\n    int mark;\n    char *name;\n    os_md5 sum;\n}file_sum;\n\n\n\n/* Internal functions prototypes */\nvoid read_controlmsg(int agentid, char *msg);\n\n\n\n\n/* Global vars, acessible every where */\nfile_sum **f_sum;\n\ntime_t _ctime;\ntime_t _stime;\n\n\n\n/* For the last message tracking */\nchar *_msg[MAX_AGENTS +1];\nchar *_keep_alive[MAX_AGENTS +1];\nint _changed[MAX_AGENTS +1];\nint modified_agentid;\n\n\n/* pthread mutex variables */\npthread_mutex_t lastmsg_mutex;\npthread_cond_t awake_mutex;\n\n\n\n/* save_controlmsg: Save a control message received\n * from an agent. read_contromsg (other thread) is going\n * to deal with it (only if message changed).\n */\nvoid save_controlmsg(int agentid, char *r_msg)\n{\n    char msg_ack[OS_FLSIZE +1];\n\n\n    /* Replying to the agent. */\n    snprintf(msg_ack, OS_FLSIZE, \"%s%s\", CONTROL_HEADER, HC_ACK);\n    send_msg(agentid, msg_ack);\n\n\n    /* Checking if there is a keep alive already for this agent. */\n    if(_keep_alive[agentid] && _msg[agentid] &&\n       (strcmp(_msg[agentid], r_msg) == 0))\n    {\n        utimes(_keep_alive[agentid], NULL);\n    }\n\n    else if(strcmp(r_msg, HC_STARTUP) == 0)\n    {\n        return;\n    }\n\n    else\n    {\n        FILE *fp;\n        char *uname = r_msg;\n        char *random_leftovers;\n\n\n        /* locking mutex. */\n        if(pthread_mutex_lock(&lastmsg_mutex) != 0)\n        {\n            merror(MUTEX_ERROR, ARGV0);\n            return;\n        }\n\n\n        /* Update rmsg. */\n        if(_msg[agentid])\n        {\n            free(_msg[agentid]);\n        }\n        os_strdup(r_msg, _msg[agentid]);\n\n\n        /* Unlocking mutex. */\n        if(pthread_mutex_unlock(&lastmsg_mutex) != 0)\n        {\n            merror(MUTEX_ERROR, ARGV0);\n            return;\n        }\n\n\n        r_msg = strchr(r_msg, '\\n');\n        if(!r_msg)\n        {\n            merror(\"%s: WARN: Invalid message from agent id: '%d'(uname)\",\n                    ARGV0,\n                    agentid);\n            return;\n        }\n\n\n        *r_msg = '\\0';\n        random_leftovers = strchr(r_msg, '\\n');\n        if(random_leftovers)\n        {\n            *random_leftovers = '\\0';\n        }\n\n\n        /* Updating the keep alive. */\n        if(!_keep_alive[agentid])\n        {\n            char agent_file[OS_SIZE_1024 +1];\n            agent_file[OS_SIZE_1024] = '\\0';\n\n            /* Writting to the agent file */\n            snprintf(agent_file, OS_SIZE_1024, \"%s/%s-%s\",\n                    AGENTINFO_DIR,\n                    keys.keyentries[agentid]->name,\n                    keys.keyentries[agentid]->ip->ip);\n\n            os_strdup(agent_file, _keep_alive[agentid]);\n        }\n\n\n        /* Writing to the file. */\n        fp = fopen(_keep_alive[agentid], \"w\");\n        if(fp)\n        {\n            fprintf(fp, \"%s\\n\", uname);\n            fclose(fp);\n        }\n    }\n\n\n    /* Locking now to notify of change.  */\n    if(pthread_mutex_lock(&lastmsg_mutex) != 0)\n    {\n        merror(MUTEX_ERROR, ARGV0);\n        return;\n    }\n\n\n    /* Assign new values */\n    _changed[agentid] = 1;\n    modified_agentid = agentid;\n\n\n    /* Signal that new data is available */\n    pthread_cond_signal(&awake_mutex);\n\n\n    /* Unlocking mutex */\n    if(pthread_mutex_unlock(&lastmsg_mutex) != 0)\n    {\n        merror(MUTEX_ERROR, ARGV0);\n        return;\n    }\n\n\n    return;\n}\n\n\n\n/* f_files: Free the files memory\n */\nvoid f_files()\n{\n    int i;\n    if(!f_sum)\n        return;\n    for(i = 0;;i++)\n    {\n        if(f_sum[i] == NULL)\n            break;\n\n        if(f_sum[i]->name)\n            free(f_sum[i]->name);\n\n        free(f_sum[i]);\n        f_sum[i] = NULL;\n    }\n\n    free(f_sum);\n    f_sum = NULL;\n}\n\n\n\n/* c_files: Create the structure with the files and checksums\n * Returns void\n */\nvoid c_files()\n{\n    DIR *dp;\n\n    struct dirent *entry;\n\n    os_md5 md5sum;\n\n    int f_size = 0;\n\n\n    f_sum = NULL;\n\n\n    /* Creating merged file. */\n    os_realloc(f_sum, (f_size +2) * sizeof(file_sum *), f_sum);\n    os_calloc(1, sizeof(file_sum), f_sum[f_size]);\n    f_sum[f_size]->mark = 0;\n    f_sum[f_size]->name = NULL;\n    f_sum[f_size]->sum[0] = '\\0';\n    MergeAppendFile(SHAREDCFG_FILE, NULL);\n    f_size++;\n\n\n\n    /* Opening the directory given */\n    dp = opendir(SHAREDCFG_DIR);\n    if(!dp)\n    {\n        merror(\"%s: Error opening directory: '%s': %s \",\n                ARGV0,\n                SHAREDCFG_DIR,\n                strerror(errno));\n        return;\n    }\n\n\n    /* Reading directory */\n    while((entry = readdir(dp)) != NULL)\n    {\n        char tmp_dir[512];\n\n        /* Just ignore . and ..  */\n        if((strcmp(entry->d_name,\".\") == 0) ||\n           (strcmp(entry->d_name,\"..\") == 0))\n        {\n            continue;\n        }\n\n        snprintf(tmp_dir, 512, \"%s/%s\", SHAREDCFG_DIR, entry->d_name);\n\n\n        /* Leaving the shared config file for later. */\n        if(strcmp(tmp_dir, SHAREDCFG_FILE) == 0)\n        {\n            continue;\n        }\n\n\n        if(OS_MD5_File(tmp_dir, md5sum) != 0)\n        {\n            merror(\"%s: Error accessing file '%s'\",ARGV0, tmp_dir);\n            continue;\n        }\n\n\n        f_sum = (file_sum **)realloc(f_sum, (f_size +2) * sizeof(file_sum *));\n        if(!f_sum)\n        {\n            ErrorExit(MEM_ERROR,ARGV0);\n        }\n\n        f_sum[f_size] = calloc(1, sizeof(file_sum));\n        if(!f_sum[f_size])\n        {\n            ErrorExit(MEM_ERROR,ARGV0);\n        }\n\n\n        strncpy(f_sum[f_size]->sum, md5sum, 32);\n        os_strdup(entry->d_name, f_sum[f_size]->name);\n        f_sum[f_size]->mark = 0;\n\n\n        MergeAppendFile(SHAREDCFG_FILE, tmp_dir);\n        f_size++;\n    }\n\n    if(f_sum != NULL)\n        f_sum[f_size] = NULL;\n\n    closedir(dp);\n\n\n    if(OS_MD5_File(SHAREDCFG_FILE, md5sum) != 0)\n    {\n        merror(\"%s: Error accessing file '%s'\",ARGV0, SHAREDCFG_FILE);\n        f_sum[0]->sum[0] = '\\0';\n    }\n    strncpy(f_sum[0]->sum, md5sum, 32);\n\n\n    os_strdup(SHAREDCFG_FILENAME, f_sum[0]->name);\n\n    return;\n}\n\n\n\n/* send_file_toagent: Sends a file to the agent.\n * Returns -1 on error\n */\nint send_file_toagent(int agentid, char *name, char *sum)\n{\n    int i = 0, n = 0;\n    char file[OS_SIZE_1024 +1];\n    char buf[OS_SIZE_1024 +1];\n\n    FILE *fp;\n\n\n    snprintf(file, OS_SIZE_1024, \"%s/%s\",SHAREDCFG_DIR, name);\n    fp = fopen(file, \"r\");\n    if(!fp)\n    {\n        merror(FOPEN_ERROR, ARGV0, file);\n        return(-1);\n    }\n\n\n    /* Sending the file name first */\n    snprintf(buf, OS_SIZE_1024, \"%s%s%s %s\\n\",\n                             CONTROL_HEADER, FILE_UPDATE_HEADER, sum, name);\n\n    if(send_msg(agentid, buf) == -1)\n    {\n        merror(SEC_ERROR,ARGV0);\n        fclose(fp);\n        return(-1);\n    }\n\n\n    /* Sending the file content */\n    while((n = fread(buf, 1, 900, fp)) > 0)\n    {\n        buf[n] = '\\0';\n\n        if(send_msg(agentid, buf) == -1)\n        {\n            merror(SEC_ERROR,ARGV0);\n            fclose(fp);\n            return(-1);\n        }\n\n        /* Sleep 1 every 30 messages -- no flood */\n        if(i > 30)\n        {\n            sleep(1);\n            i = 0;\n        }\n        i++;\n    }\n\n\n    /* Sending the message to close the file */\n    snprintf(buf, OS_SIZE_1024, \"%s%s\", CONTROL_HEADER, FILE_CLOSE_HEADER);\n    if(send_msg(agentid, buf) == -1)\n    {\n        merror(SEC_ERROR,ARGV0);\n        fclose(fp);\n        return(-1);\n    }\n\n\n    fclose(fp);\n\n    return(0);\n}\n\n\n\n/** void read_contromsg(int agentid, char *msg) v0.2.\n * Reads the available control message from\n * the agent.\n */\nvoid read_controlmsg(int agentid, char *msg)\n{\n    int i;\n\n\n    /* Remove uname */\n    msg = strchr(msg,'\\n');\n    if(!msg)\n    {\n        merror(\"%s: Invalid message from '%d' (uname)\",ARGV0, agentid);\n        return;\n    }\n\n\n    *msg = '\\0';\n    msg++;\n\n\n    if(!f_sum)\n    {\n        /* Nothing to share with agent */\n        return;\n    }\n\n\n    /* Parse message */\n    while(*msg != '\\0')\n    {\n        char *md5;\n        char *file;\n\n        md5 = msg;\n        file = msg;\n\n        msg = strchr(msg, '\\n');\n        if(!msg)\n        {\n            merror(\"%s: Invalid message from '%s' (strchr \\\\n)\",\n                        ARGV0,\n                        keys.keyentries[agentid]->ip->ip);\n            break;\n        }\n\n        *msg = '\\0';\n        msg++;\n\n        file = strchr(file, ' ');\n        if(!file)\n        {\n            merror(\"%s: Invalid message from '%s' (strchr ' ')\",\n                        ARGV0,\n                        keys.keyentries[agentid]->ip->ip);\n            break;\n        }\n\n        *file = '\\0';\n        file++;\n\n\n        /* New agents only have merged.mg. */\n        if(strcmp(file, SHAREDCFG_FILENAME) == 0)\n        {\n            if(strcmp(f_sum[0]->sum, md5) != 0)\n            {\n                debug1(\"%s: DEBUG Sending file '%s' to agent.\", ARGV0,\n                       f_sum[0]->name);\n                if(send_file_toagent(agentid,f_sum[0]->name,f_sum[0]->sum)<0)\n                {\n                    merror(\"%s: ERROR: Unable to send file '%s' to agent.\",\n                            ARGV0,\n                            f_sum[0]->name);\n                }\n            }\n\n            i = 0;\n            while(f_sum[i])\n            {\n                f_sum[i]->mark = 0;\n                i++;\n            }\n\n            return;\n        }\n\n\n        for(i = 1;;i++)\n        {\n            if(f_sum[i] == NULL)\n                break;\n\n            else if(strcmp(f_sum[i]->name, file) != 0)\n                continue;\n\n            else if(strcmp(f_sum[i]->sum, md5) != 0)\n                f_sum[i]->mark = 1; /* Marked to update */\n\n            else\n            {\n                f_sum[i]->mark = 2;\n            }\n            break;\n        }\n    }\n\n\n    /* Updating each file marked */\n    for(i = 1;;i++)\n    {\n        if(f_sum[i] == NULL)\n            break;\n\n        if((f_sum[i]->mark == 1) ||\n           (f_sum[i]->mark == 0))\n        {\n\n            debug1(\"%s: Sending file '%s' to agent.\", ARGV0, f_sum[i]->name);\n            if(send_file_toagent(agentid,f_sum[i]->name,f_sum[i]->sum) < 0)\n            {\n                merror(\"%s: Error sending file '%s' to agent.\",\n                        ARGV0,\n                        f_sum[i]->name);\n            }\n        }\n\n        f_sum[i]->mark = 0;\n    }\n\n\n    return;\n}\n\n\n\n/** void *wait_for_msgs(void *none) v0.1\n * Wait for new messages to read.\n * The messages are going to be sent from save_controlmsg.\n */\nvoid *wait_for_msgs(void *none)\n{\n    int id, i;\n    char msg[OS_SIZE_1024 +2];\n\n\n    /* Initializing the memory */\n    memset(msg, '\\0', OS_SIZE_1024 +2);\n\n\n    /* should never leave this loop */\n    while(1)\n    {\n        /* Every NOTIFY * 30 minutes, re read the files.\n         * If something changed, notify all agents\n         */\n        _ctime = time(0);\n        if((_ctime - _stime) > (NOTIFY_TIME*30))\n        {\n            f_files();\n            c_files();\n\n            _stime = _ctime;\n        }\n\n\n        /* locking mutex */\n        if(pthread_mutex_lock(&lastmsg_mutex) != 0)\n        {\n            merror(MUTEX_ERROR, ARGV0);\n            return(NULL);\n        }\n\n        /* If no agent changed, wait for signal */\n        if(modified_agentid == -1)\n        {\n            pthread_cond_wait(&awake_mutex, &lastmsg_mutex);\n        }\n\n        /* Unlocking mutex */\n        if(pthread_mutex_unlock(&lastmsg_mutex) != 0)\n        {\n            merror(MUTEX_ERROR, ARGV0);\n            return(NULL);\n        }\n\n\n        /* Checking if any agent is ready */\n        for(i = 0;i<keys.keysize; i++)\n        {\n            /* If agent wasn't changed, try next */\n            if(_changed[i] != 1)\n            {\n                continue;\n            }\n\n            id = 0;\n\n            /* locking mutex */\n            if(pthread_mutex_lock(&lastmsg_mutex) != 0)\n            {\n                merror(MUTEX_ERROR, ARGV0);\n                break;\n            }\n\n            if(_msg[i])\n            {\n                /* Copying the message to be analyzed */\n                strncpy(msg, _msg[i], OS_SIZE_1024);\n                _changed[i] = 0;\n\n                if(modified_agentid >= i)\n                {\n                    modified_agentid = -1;\n                }\n\n                id = 1;\n            }\n\n            /* Unlocking mutex */\n            if(pthread_mutex_unlock(&lastmsg_mutex) != 0)\n            {\n                merror(MUTEX_ERROR, ARGV0);\n                break;\n            }\n\n            if(id)\n            {\n                read_controlmsg(i, msg);\n            }\n        }\n    }\n\n    return(NULL);\n}\n\n\n\n/* manager_init: Should be called before anything here */\nvoid manager_init(int isUpdate)\n{\n    int i;\n    _stime = time(0);\n\n    f_files();\n    c_files();\n\n    debug1(\"%s: DEBUG: Running manager_init\", ARGV0);\n\n    for(i=0; i<MAX_AGENTS +1; i++)\n    {\n        _keep_alive[i] = NULL;\n        _msg[i] = NULL;\n        _changed[i] = 0;\n    }\n\n    /* Initializing mutexes */\n    if(isUpdate == 0)\n    {\n        pthread_mutex_init(&lastmsg_mutex, NULL);\n        pthread_cond_init(&awake_mutex, NULL);\n    }\n\n    modified_agentid = -1;\n\n    return;\n}\n\n\n\n/* EOF */\n",
          "name": "Function does not handle null terminated strings or invalid pointers properly",
          "filename": "manager.c"
        }
      }

Expected behavior

The input vulnerability_description must be provided to the AI Gateway, so that it can be used in the prompt here: resolve_vulnerability/user/1.0.0.jinja#L5.

/cc @nmccorrison @mclausen35