VYPR
Moderate severityNVD Advisory· Published Dec 6, 2019· Updated Aug 5, 2024

CVE-2019-19624

CVE-2019-19624

Description

An out-of-bounds read was discovered in OpenCV before 4.1.1. Specifically, variable coarsest_scale is assumed to be greater than or equal to finest_scale within the calc()/ocl_calc() functions in dis_flow.cpp. However, this is not true when dealing with small images, leading to an out-of-bounds read of the heap-allocated arrays Ux and Uy.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

OpenCV before 4.1.1 has an out-of-bounds read in DISOpticalFlow due to incorrect scale assumptions for small images, potentially leading to information disclosure.

Vulnerability

Details

An out-of-bounds read vulnerability exists in OpenCV versions prior to 4.1.1 within the calc() and ocl_calc() functions of dis_flow.cpp. The root cause is an incorrect assumption that the variable coarsest_scale is always greater than or equal to finest_scale. When processing small images, this assumption fails, leading to an out-of-bounds read of the heap-allocated arrays Ux and Uy [1][3].

Exploitation

Exploitation requires an attacker to supply a crafted small image to an application that uses OpenCV's DISOpticalFlow algorithm. No authentication is needed if the application processes untrusted images, and the attack can be triggered remotely if the application accepts image inputs over a network [1][3].

Impact

A successful out-of-bounds read can result in the disclosure of heap memory contents, potentially leaking sensitive information. The vulnerability does not directly enable code execution, but information leakage may aid further attacks [1][3].

Mitigation

The issue was fixed in OpenCV version 4.1.1 via commit d1615ba, which introduced functions autoSelectCoarsestScale and autoSelectPatchSizeAndScales to properly handle small images. Users are advised to update to OpenCV 4.1.1 or later [4].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
opencv-pythonPyPI
< 4.1.0.254.1.0.25
opencv-python-headlessPyPI
< 4.1.0.254.1.0.25
opencv-contrib-pythonPyPI
< 4.1.0.254.1.0.25
opencv-contrib-python-headlessPyPI
< 4.1.0.254.1.0.25

Affected products

5

Patches

1
d1615ba11a93

video:fixed DISOpticalFlow segfault from small img

https://github.com/opencv/opencvThang TranMay 27, 2019via ghsa
2 files changed · +93 2
  • modules/video/src/dis_flow.cpp+65 2 modified
    @@ -140,6 +140,8 @@ class DISOpticalFlowImpl CV_FINAL : public DISOpticalFlow
         void prepareBuffers(Mat &I0, Mat &I1, Mat &flow, bool use_flow);
         void precomputeStructureTensor(Mat &dst_I0xx, Mat &dst_I0yy, Mat &dst_I0xy, Mat &dst_I0x, Mat &dst_I0y, Mat &I0x,
                                        Mat &I0y);
    +    int autoSelectCoarsestScale(int img_width);
    +    void autoSelectPatchSizeAndScales(int img_width);
     
         struct PatchInverseSearch_ParBody : public ParallelLoopBody
         {
    @@ -435,6 +437,44 @@ void DISOpticalFlowImpl::precomputeStructureTensor(Mat &dst_I0xx, Mat &dst_I0yy,
         }
     }
     
    +int DISOpticalFlowImpl::autoSelectCoarsestScale(int img_width)
    +{
    +    const int fratio = 5;
    +    return std::max(0, (int)std::floor(log2((2.0f*(float)img_width) / ((float)fratio * (float)patch_size))));
    +}
    +
    +void DISOpticalFlowImpl::autoSelectPatchSizeAndScales(int img_width)
    +{
    +    switch (finest_scale)
    +    {
    +    case 1:
    +        patch_size = 8;
    +        coarsest_scale = autoSelectCoarsestScale(img_width);
    +        finest_scale = std::max(coarsest_scale-2, 0);
    +        break;
    +
    +    case 3:
    +        patch_size = 12;
    +        coarsest_scale = autoSelectCoarsestScale(img_width);
    +        finest_scale = std::max(coarsest_scale-4, 0);
    +        break;
    +
    +    case 4:
    +        patch_size = 12;
    +        coarsest_scale = autoSelectCoarsestScale(img_width);
    +        finest_scale = std::max(coarsest_scale-5, 0);
    +        break;
    +
    +    // default case, fall-through.
    +    case 2:
    +    default:
    +        patch_size = 8;
    +        coarsest_scale = autoSelectCoarsestScale(img_width);
    +        finest_scale = std::max(coarsest_scale-2, 0);
    +        break;
    +    }
    +}
    +
     DISOpticalFlowImpl::PatchInverseSearch_ParBody::PatchInverseSearch_ParBody(DISOpticalFlowImpl &_dis, int _nstripes,
                                                                                int _hs, Mat &dst_Sx, Mat &dst_Sy,
                                                                                Mat &src_Ux, Mat &src_Uy, Mat &_I0, Mat &_I1,
    @@ -1318,9 +1358,20 @@ bool DISOpticalFlowImpl::ocl_calc(InputArray I0, InputArray I1, InputOutputArray
         else
             flow.create(I1Mat.size(), CV_32FC2);
         UMat &u_flowMat = flow.getUMatRef();
    -    coarsest_scale = min((int)(log(max(I0Mat.cols, I0Mat.rows) / (4.0 * patch_size)) / log(2.0) + 0.5), /* Original code serach for maximal movement of width/4 */
    +    coarsest_scale = min((int)(log(max(I0Mat.cols, I0Mat.rows) / (4.0 * patch_size)) / log(2.0) + 0.5), /* Original code search for maximal movement of width/4 */
                              (int)(log(min(I0Mat.cols, I0Mat.rows) / patch_size) / log(2.0)));              /* Deepest pyramid level greater or equal than patch*/
     
    +    if (coarsest_scale<0)
    +        CV_Error(cv::Error::StsBadSize, "The input image must have either width or height >= 12");
    +
    +    if (coarsest_scale<finest_scale)
    +    {
    +        // choose the finest level based on coarsest level.
    +        // Refs: https://github.com/tikroeger/OF_DIS/blob/2c9f2a674f3128d3a41c10e41cc9f3a35bb1b523/run_dense.cpp#L239
    +        int original_img_width = I0.size().width;
    +        autoSelectPatchSizeAndScales(original_img_width);
    +    }
    +
         ocl_prepareBuffers(I0Mat, I1Mat, u_flowMat, use_input_flow);
         u_Ux[coarsest_scale].setTo(0.0f);
         u_Uy[coarsest_scale].setTo(0.0f);
    @@ -1385,8 +1436,20 @@ void DISOpticalFlowImpl::calc(InputArray I0, InputArray I1, InputOutputArray flo
         else
             flow.create(I1Mat.size(), CV_32FC2);
         Mat flowMat = flow.getMat();
    -    coarsest_scale = min((int)(log(max(I0Mat.cols, I0Mat.rows) / (4.0 * patch_size)) / log(2.0) + 0.5), /* Original code serach for maximal movement of width/4 */
    +    coarsest_scale = min((int)(log(max(I0Mat.cols, I0Mat.rows) / (4.0 * patch_size)) / log(2.0) + 0.5), /* Original code search for maximal movement of width/4 */
                              (int)(log(min(I0Mat.cols, I0Mat.rows) / patch_size) / log(2.0)));              /* Deepest pyramid level greater or equal than patch*/
    +
    +    if (coarsest_scale<0)
    +        CV_Error(cv::Error::StsBadSize, "The input image must have either width or height >= 12");
    +
    +    if (coarsest_scale<finest_scale)
    +    {
    +        // choose the finest level based on coarsest level.
    +        // Refs: https://github.com/tikroeger/OF_DIS/blob/2c9f2a674f3128d3a41c10e41cc9f3a35bb1b523/run_dense.cpp#L239
    +        int original_img_width = I0.size().width;
    +        autoSelectPatchSizeAndScales(original_img_width);
    +    }
    +
         int num_stripes = getNumThreads();
     
         prepareBuffers(I0Mat, I1Mat, flowMat, use_input_flow);
    
  • modules/video/test/test_OF_accuracy.cpp+28 0 modified
    @@ -121,6 +121,34 @@ TEST(DenseOpticalFlow_DIS, ReferenceAccuracy)
         }
     }
     
    +TEST(DenseOpticalFlow_DIS, InvalidImgSize_CoarsestLevelLessThanZero)
    +{
    +    cv::Ptr<cv::DISOpticalFlow> of = cv::DISOpticalFlow::create();
    +    const int mat_size = 10;
    +
    +    cv::Mat x(mat_size, mat_size, CV_8UC1, 42);
    +    cv::Mat y(mat_size, mat_size, CV_8UC1, 42);
    +    cv::Mat flow;
    +
    +    ASSERT_THROW(of->calc(x, y, flow), cv::Exception);
    +}
    +
    +// make sure that autoSelectPatchSizeAndScales() works properly.
    +TEST(DenseOpticalFlow_DIS, InvalidImgSize_CoarsestLevelLessThanFinestLevel)
    +{
    +    cv::Ptr<cv::DISOpticalFlow> of = cv::DISOpticalFlow::create();
    +    const int mat_size = 80;
    +
    +    cv::Mat x(mat_size, mat_size, CV_8UC1, 42);
    +    cv::Mat y(mat_size, mat_size, CV_8UC1, 42);
    +    cv::Mat flow;
    +
    +    of->calc(x, y, flow);
    +
    +    ASSERT_EQ(flow.rows, mat_size);
    +    ASSERT_EQ(flow.cols, mat_size);
    +}
    +
     TEST(DenseOpticalFlow_VariationalRefinement, ReferenceAccuracy)
     {
         Mat frame1, frame2, GT;
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.